<-- Capítulo

Índice del tutor de Delphi
© Copyright 1998
por David Martínez.

Todos los derechos reservados

Artículo: Consideraciones de Diseño

Introducción

Como usted probablemente sabrá, el mundo de la computación es muy amplio. Es difícil convertirse en un experto en un programa en específico, incluso si el programa es simplemente un procesador de palabras. Algunas personas están tán acostumbradas a MS-Word que casi hay que amarrarlas para desinstalar Word de sus máquinas y poner Wordperfect, o viceversa.

Este sentimiento no para con los programas. De hecho, se hace aún más excacerbado en cuanto se refiere a Sistemas Operativos (quién no ha oido el pleito Windows vs. Linux vs. Solaris...), computadoras (PCs vs. Macs vs. Amigas vs. BeBox...), y también lenguages y técnicas de programación.

Este articulo tiene dos objetivos:

  1. Explicar un poco el porqué de estas tendencias y la historia detrás de los campos del desarrollo.
  2. Ayudarle a hacer buenas decisiones de diseño basadas en el conocimiento de estas tendencias.

¿Porqué Puede Usted Confiar en Mí?

En las guerras siempre hay desconfianza. Si usted está obsesionado con, digamos, Visual Basic, de inmediato va a desconfiar de una persona que programa en Delphi. Si usted es un "Linuxero", de inmediato va a desconfiar de Microsoft.

Yo mismo he sido culpable de añadir leña al problema. Soy muy entusiasta acerca de las nuevas tecnologías y a veces debo admitir que me paso. Pero después de tanto tiempo de ganar unas y perder otras he aprendido varias cosas que creo que le servirán como consejo y para mejorar su carrera.

Básicamente, la razón por la cual puede confiar en mí es que yo no estoy tratando de venderle nada. Estos consejos están aquí, para quien los quiera leer (y posiblemente opinar). No me importa si los sigue o no, pero creo que le conviene leerlos y formarse su propia impresion. Y si no sabe mucho de las diferentes culturas que han chocado con el paso de los años para formar este mundo de Internet, Mainframes, PCs y Windows, le conviene aprender al menos un poco de la historia. Creo que fué Cervantes quien dijo: "Quien no conoce la historia está condenado a repetirla".

El "Viejo Oeste" de la Computación

En los viejos tiempos, las computadoras valían un millon de dólares, y solo universitarios estudiando ingenierías tenían acceso a ellas. La gente se juntaba en "clubs" para pedir "tiempo de máquina". El ambiente era bastante elitista, pero de una manera positiva, porque se basaba unicamente en tu capacidad mental (y el hecho de que estabas en la universidad).

Algunas de estas personas también eran muy capaces ingenieros electrónicos y comenzaron a usar los nuevos microprocesadores que HP utilizaba en sus calculadoras financieras para crear computadoras pequeñas, como la Apple y Commodore.

Aqui es donde la primera separación seria dió lugar. Los académicos, acostumbrados a computadoras con "sistemas operativos de a deveras", ignoraron y se rieron de estas maquinitas. Pero mientras los académicos seguían utilizando UNIX y VAX y VMS para fines científicos, los emprendedores que crearon las computadoras pequeñas por bajo precio comenzaron a crear prográmas prácticos para sus maquinítas (contabilidad, etc).

Fué con la invención de la hoja de Cálculo Visicalc que la gente en general comenzó a comprar computadoras porque esta facilidad por sí sola justificaba el costo de la máquina. Muy pronto la computación, el arte que desde afuera seguía siendo el dominio de nerds y "techies", se partió en dos campos: Los "científicos" (academicos), y los "prácticos" (emprendedores).

Pero la diferencia entre las poderosas máquinas de los universitarios (que eran accesadas mediante terminales para ahorrar dinero y no tener que comprar tantas) y los "juguetes computacionales" como la Apple e IBM PC todavía era demasiado grande, así que los dos campos tuvieron un desarrollo donde más que nada se ignoraron unos a los otros.

¿Quién tenía razón? ¿Cuál era la mejor máquina? Hoy en día en realidad no importa. Por un lado, los científicos tenían "verdaderos" sistemas operativos, diseñados para manejar multiples usuarios, con seguridad y multitarea integrada. Pero estos sistemas eran tan pesados que ninguna computadora que la gente común podía comprar era suficiente para correr tan siquiera una partecita del sistema operativo, mucho menos las aplicaciones de los usuarios. En el otro campo, los fabricantes de máquinas pequeñas encontraron que al público no le interesaba la ciencia, sino lo que la máquina podía hacer, y el hecho de que podían escribir cartas, libros y balancear sus cuentas bancarias.

Esto funcionó muy bien, manteniendo a los prácticos lejos de los científicos hasta que dos eventos ocurrieron:

El primer evento fué que las PCs comenzaron a tener suficiente poder bruto de proceso para competir con las máquinas de los científicos, pero su sistema operativo era aún muy primitivo (DOS), y como a los clientes no les importaba la ciencia, las compañías no lo iban a mejorar (especialmente porque no les dejaría dinero. Los esfuerzos para conectarlas en red se limitaban a compartir archivos via redes muy caras de una compañía llamada Novell. Las redes con protocolo IPX eran muy prácticas, pero nunca fueron planeadas para crecer más allá de la comunicación interna de una o dos compañías.

El otro evento fué que los universitarios, acostumbrados desde siempre a que sus sistemas multiusuario tenían correo electrónico integrado y siguiendo con la evolución obvia de los sistemas grandes (que para entonces ya no eran tan caros), comenzaron a utilizar sus excelentes, científicos y bien planeados protocolos de comunicación en redes para interconectar las universidades utilizando líneas dedicadas y las nuevas líneas de comunicación digital. Para entonces muchos de ellos también eran usuarios de PCs y crearon implementaciones de los mismos protocolos para sus pequeñas máquinas para poderse conectar a lo que después se llamaría el Internet.

Choque de Culturas

La presente lucha entre Windows vs. Linux es una pelea que ha estado siendo preparada por más de veinte años, y a mi manera de ver el problema es un choque entre dos culturas diferentes más que entre dos productos. Cada uno de estos productos tiene una filosofía y una manera específica de hacer las cosas. Pero solo ahora que las computadoras pequeñas pueden correr un sistema tipo UNIX con facilidad es cuando la pregunta "¿Porqué seguimos usando Windows?" viene a la mente.

En mi opinión, estamos en el 1492 de la computación. Dos mundos se han encontrado, y no hay marcha atrás. La diferencia de este encuentro con todos los demás que han tenido un ganador es que ambas plataformas han sido utilizadas por más de diez años, y ambas tienen una gran base instalada, así que a los escépticos de ambos campos les digo: Tu "enemigo" (ya sea Windows o Linux/Unix, etc) no se va a ir a ningún lado. Y como se dice por ahí: Cualquier persona que ofrece una sola tecnología como solución a todos los problemas de la humanidad sufre de fanatismo. Esto incluye tanto a Linux como a Windows, tanto a Delphi como a Java.

Windows no va a desaparecer por la simple y sencilla razón de que todos los programas están escritos para Windows y Bill Gates tiene más dinero que Singapur. Y Unix/Linux no va a desaparecer por la simple y sencilla razón de que es libre, seguro, portable a cualquier clase de Hardware y casi todos los servidores de Internet funcionan en Linux. Así que mientras haya programadores Linux seguirá vivo, sin importar lo que le pase al Señor Torvalds.

He escrito esta gran introducción a mis consideraciones de diseño para explicarle porqué es muy importante estar al tanto de lo que pasa en el campo de Windows (si usted es programador en Linux) y también de lo que pasa en el campo de Linux (si usted programa en Windows). Y no porque el mundo vaya a cambiar y nuestro lenguaje de programación vaya a desaparecer (lo cual despertaría nuestro sentido de supervivencia y nos haría gastar energías a lo menso en pelear que nuestro lenguaje preferido sobreviviera), sino porque un día de estos una máquina "diferente" va a aparecer en su centro de cómputo, y si usted tiene una base de teorías de diseño independiente de cualquier lenguaje o sistema operativo, usted podrá adaptarse mejor a nuevos lenguajes y sistemas. El entender Interfaces COM y CORBA y las ideas de diseño relevantes a estas interfaces también ayudará a que usted y los muchachos del campo contrario se entiendan y escriban soluciones que satisfagan al sus usuarios (y jefes) en vez de presentar una fea y muy poco profesional pelea de nerds.

Mis Preceptos de Diseño

Advertencia

Estos preceptos no son de un Universitario ni de un letrado. Pero mi obsesión por saber exactamente como funciona la tecnología me ha hecho darme cuenta de ciertas constantes de diseño que en mi opinión son, digamos, "saludables". Como esta es mi muy particular percepción del mundo de la arquitectura de sistemas de software, es muy posible que tanto académicos como prácticos decidan que estoy mal, loco o peor, así que por favor, mándeme sus opiniones pero quédese sus flamazos.

Otro detalle: Hoy día soy programador de Delphi en Win32 (así que algunos de mis ejemplos están más enfocados a Delphi), pero estos ejemplos provienen de mi experiencia como programador en general, así que sea usted programador de Delphi, Visual Basic, cualquier Unix Shell, Python, Tcl/tk, etcétera, hay algo de importancia para usted, porque he evitado escribir codigo hasta donde me fué posible.

La importancia de stdin, stdout y stderr

Casi todos los programadores de sistemas DOS y Windows que hayan aprendido de manera práctica en el mundo de la programación "Visual" ignoran uno de los conceptos más importantes de programación: La importancia de stdin, stdout y stderr. Los programadores de Unix viven escuchando en stdin y hablando en stdout, mientras insultan en stderr. Casi la totalidad de los programas pequeños en Unix pueden recibir sus datos via stdin y pueden expulsar sus datos via stdout sin ningún problema. De hecho, todos los lenguajes en Unix siempre tienen disponible el stdin mediante una llamada a fileopen. Es tal como abrir un archivo, así que es fácil utilizar la misma lógica para abrir un archivo real que para abrir el "archivo" de stdin. Esto es lo que permite en Unix y Linux utilizar el siguiente comando para saber cuantos archivos me pertenencen:

  ls -l | grep "david" | wc -l

Como podrán ver, este comando está corriendo tres programas: "ls" (directorio), "grep" (filtro) y "wc" (contar palabras o líneas). Todo estos están encadenados con la barra, que toma el stdout del programa a su izquierda y lo pasa como stdin al programa a la derecha. Aún con Delphi, para saber qué archivos me pertenecen en NT, hubiera tenido que hacer lo siguiente:

  1. Abrir el directorio de *.* y crear un TFileRec
  2. Llamar al Win32 API para averiguar el SUID de "david"
  3. Hacer un do while para que ejecute mientras FileRec no sea NIL
  4. Utilizar FileOpen y el Win32 API para averiguar de quién es el archivo
  5. Si el SUID es el mismo que el SUID de "david", incrementar un contador

Mi programa en Delphi me hubiera tomado unos cuantos minutos, pero sería un poquito pesado (como 250K o algo así). En lugar de estas complicaciones, tres comandos que vienen con Unix me pueden decir lo mismo, gracias a que los comandos son utilerías generales y entienden stdin y stdout. Además, esta línea de comando toma como diez segundos de pensarla y escribirla, si usted sabe al menos un poco de Unix/Linux.

Moraleja: Si usted hace procesos "nocturnos", asegúrese de que sus programas tengan una manera de usar sólamente la consola (utilizando parámetros en la línea de comando), de que entiendan stdin/stdout, y que emitan sus errores a stderr, aún si usted duda que a alguien le importe. Solo después de haber hecho esto comienze a poner un programa interactivo con ventanitas que ejecute el programa que realmente realiza el proceso.

Abstracción de los datos y separación de datos e interfaz del usuario

El problema de las herramientas RAD (Rapid Application Development) es que hacen demasiado fácil poner las reglas del negocio dentro de los eventos de los campos visuales de la aplicación. La aplicación funciona, pero no es reutilizable. Es en extremo importante asegurarse de que los campos visuales llamen una especie de "servicio" sin interfaz de usuario, y de que sea éste servicio el que de diga a la interfaz de usuario si datos específicos son válidos o no, los resultados de los campos calculados, etcétera. Después de 3 veces de escribir el mismo algoritmo para calcular el total de una factura, pudo haber creado un servicio reutilizable que hace todos los cálculos por usted. ¡Y para la vez número 15 o 16, se puede haber vuelto loco!

Interfaces, Interfaces, Interfaces

Y ya que estamos hablando de la importancia de separar los datos y la interfaz del usuario, demos un paso más y comencemos a pensar en reuso de código no solo entre nuestros propios proyectos, sino entre su proyecto y los proyectos de otros grupos de trabajo u organizaciones que a lo mejor ni siquiera tienen el lenguaje que usted utiliza. ¿Qué hacemos con ellos?

El publicar interfaces (ya sea para usted mismo, para otros grupos de trabajo o incluso para vender su producto para uso en otras compañías) es un paso muy importante que requiere un conocimiento del problema que su programa debe resolver que muchas veces va más allá de la capacidad de un programador por sí mismo. Es importante que antes de publicar una interface usted esté muy consciente de las entidades del mundo real que usted está modelando, y que aplique modelos de programación probados (como el Model-View-Controller) para que otras aplicaciones se puedan conectar. Cuando usted publique su interfaz siempre implemente al menos una funcion de Callback para decirle al programa cliente que actualice su pantalla (vea mi artículo "Entendiendo el Paradigma de Model View Controller" - TODO: Escribir artículo :-) para mayor información).

Lea acerca de Patrones de Diseño

En los últimos años, algunos programadores con experiencia han comenzado a identificar "tipos" de problemas en lugar de problemas en sí. Este proceso de pensamiento usualmente termina con lo que llamamos un "patrón de diseño" (Design Pattern). Los patrones de diseño a veces vienen con código de ejemplo o a veces son sólo la idea con "pseudocódigo". Es importante que usted lea un libro acerca de patrones de diseño y se familiarice con esta clase de pensamiento. Ésto le dará no solo más experiencia, sino bastantes ideas de como mejorar sus propios programas. Si usted tiene ya un par de sistemas bajo su cuidado, incluso podrá reconocer áreas donde usted aplicó (o pudo haber aplicado) estos patrones.

Porqué el usar el Registro de Windows (y cosas por el estilo) no siempre es una buena idea

Aqui voy a blasfemar un poquito y decir que el "Registro" en Windows es probablemente la peor idea que ha salido de Redmond. Seguramente voy a recibir flamazos por e-mail por el enunciado anterior, así que por favor escuche mi explicación.

La idea del registro como un repositorio central de configuración con interfaz gráfica para modificarlo es muy loable, pero la manera en que está implementado es simplemente un error garrafal. Si usted tenía un problema de configuración básica en Windows 3.1 que hacía que Windows no funcionara, lo peor que podía ocurrir es que usted tendría que recuperar su respaldo del archivo WIN.INI y/o SYSTEM.INI y usted estaba de regreso en Windows, desde donde podía seguir componiendo las cosas. No hay nada de malo con tratar de hacer una interfaz gráfica para centralizar la configuración, pero el no poder utilizar un editor de textos estándar impide al usuario con experiencia modificar algo.

No solo esto, sino que algunos programas, por el motivo que sea, pueden causar corrupción en el registro de Windows. En mi propia máquina Windows NT he tenido que reinstalar todos los programas que añaden información al folder HKEY_CURRENT_USER más de una vez porque el archivo USER.DAT del registro (que es binario) se corrompió y no hay manera de corregirlo.

Otro problema es la dificulta de mover aplicaciones. Si usted tiene una aplicación de Windows que requiere de la existencia de información específica en el registro, no la puede copiar a otra máquina (y muchas veces ni siquiera puede cambiar el folder en la misma máquina) porque el registro se confunde o desaparece. Esto resta flexibilidad cuando lo compara con un programa con un archivo .INI junto al ejecutable.

Mi recomendación es, al contrario de Microsoft, que utilice el registro tan poco como sea posible. No hay nada de malo en usarlo para ciertas cosas, pero siempre pese los pros contra los contras con cada grupo de configuración que necesite grabar a disco. En general, a mi me gusta hacer un directorio llamado DATA o CONFIG bajo el directorio principal del ejecutable.

Si necesita guardar datos basados en cada usuario (como lo haría con HKEY_CURRENT_USER), LEA el registro para averiguar cuál es el directorio de documentos del usuario (en el valor HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders\Personal) y guarde sus datos en un directorio con un nombre como ".miaplicacion" bajo este directorio de documentos. Esta es la usanza en Unix y le será fácil acostumbrarse a nuevos ambientes operativos más tarde. Por cierto: ¡Nunca asuma que el directorio siempre va a ser "My Documents"!.

Aprende a Utilizar Hilos de Ejecución, pero se Consciente del número de hilos que usas

La programación por "Hilos de Ejecución" es más compleja que la programación normal. Pero hoy día casi todas las soluciones que utilizan interfaces requieren el uso de hilos (threads) de ejecución. Algunas utilerías manejan un hilo de ejecución por cada conexión. Esto funciona muy bien con pocos clientes, pero si usted comienza a tener más y más usuarios comenzará a tener problemas. Esto es porque el procesador ocupa más y más tiempo cambiando entre una tarea y otra que trabajando. La solución es establecer algo llamado Thread Pool, que es una pequeña serie de hilos de ejecución que hacen el verdadero trabajo, y los puntos de entrada de la interfaz solo encuentran un "hilo" que no esté haciendo nada, lo agarran y le piden que ejecute la función.

Además, bajo ciertas circunstancias debes ser consciente de que a lo mejor es más productivo (especialmente bajo Linux) ejecutar varios procesos en vez de varios hilos. Esto no es muy conveniente en Windows porque bajo Windows la ejecución de un proceso nuevo toma demasiado tiempo, pero bajo otros sistemas operativos, un proceso extra (especialmente si es pequeño) puede ser la mejor opción.

Siempre ten en Mente "State" contra "Stateless"

Cuando usted está conectado a un servidor que ha publicado una interface, la interface usualmente tiene un objeto en el otro lado (representado en el cliente por un "puntero de interfaz") que muchas veces mantiene valores de ciertas variables. Estos valores que el servidor mantiene se llaman "estado" o "State". Una aplicación "Stateless" es una aplicación que no necesita guardar el estado del objeto en el servidor porque todas las peticiones de los clientes son "atómicas", o sea un tipo pregunta/respuesta en vez de una conversación.

Aún cuando en teoría COM y CORBA le permiten guardar información "State", procure no hacerlo, o si en realidad la necesita, guardar la información en la base de datos con un identificador de sesión o algo así. Esto le permite escribir lógica de reconexión automática en sus clientes (no hay nada que dé mas coraje que perder las modificaciones a una pantalla (o peor aún, a la aplicación) simplemente porque a la red le dió hipo y nuestro cliente perdió el puntero a la conexión. Si usted tiene un sistema "Stateless" o un modo sencillo de recuperar información de "State".

Trate de Utilizar Estándares para Comunicación

Los expertos de los comités de estándares siempre están saliendo con nuevas cosas. HTML, por ejemplo, salió del consorcio W3. Ahora hay un nuevo estándar que todas las compañías están adoptando llamado XML. Mi recomendación es que utilice XML en cuanto pueda, y que sus servicios se comuniquen entre sí mediante XML. Otra recomendación es que utilice CORBA en vez de COM para la comunicación entre sus interfaces.

Si por algún motivo no puede utilizar XML, trate de usar algo que se le parezca. Evite los protocolos binarios a toda costa! Esto incluye incluso cosas como comunicación MIDAS. Si su aplicación puede hacerse enviando cadenas ASCII en XML via CORBA en vez de un protocolo proprietario (como MIDAS/DCOM o ADO), le será más facil a los señores de Organización XYZ utilizar COBOL en su mainframe (o Java en su Solaris)

Automatice su código con utilerías y trabajos nocturnos

Aquí estamos, los creadores de un mundo de automatización. Nos piden que automaticemos todos los aspectos de una empresa. Pero cuando necesitamos hacer algo con nuestro código una y otra vez, ¿qué hacemos? ¡Nos ponemos a cortar y pegar una y otra vez en 1000 archivos de código fuente!

Después nos piden compilar nuestro maravilloso sistema maestro de automatización empresarial una vez a la semana para nuestros testers. ¿Y qué hacemos? Una vez a la semana nos sentamos media hora para meter nuestro trabajo en el programa de control de versiones, sacarlo de nuevo, poner una etiqueta, y construir el ejecutable - ¡A mano!

Hay filosofía aquí, pero no la encuentro.

Lo que sí hay es un poco de ironía, y también un sentimiento de que eso no está bien. Automatice sus procesos! Utilice lenguajes y utilerías capaces de manipular texto fácilmente utilizando expresiones regulares (regex) estándar "POSIX" (como Perl, awk o sed) para automatizar sus cambios globales de código. El automatizar cambios tan simples como encabezados con su copyright en todos sus programas fuente le ahorrarían más tiempo del que usted cree. Incluso si "le da miedo" modificar su código fuente programáticamente puede tomar ventaja de las utilerías y de su capacidad de búsqueda. Por ejemplo:

Usted puede crear un proceso nocturno en Perl que examina todo su código fuente y busca palabras clave dentro de comentarios como "// TAREA:" o "// ERROR:" y los envía por correo electrónico a usted (el programador). ¡Felicidades! ¡Acaba de hacer una lista de tareas automatizada!

También puede instalar las utilerías GNU para Windows (CygWin) y crear archivos "make" para compilar su proyecto todas las noches. Examine los ejecutables en su programa de control de versiones. Casi todos tienen programas de consola que usted puede encadenar con un archivo batch (o Shell, si instala cygwin) para que por las noches (mediante el comando AT de Windows NT) su proyecto compile automáticamente y le envíe los "warnings" y posibles errores por correo electrónico. ¡Listo! Ahora usted lo único que tiene que hacer es asegurarse de que el Viernes antes de irse a casa la última versión de su programa compile. El Lunes tendrá el "ejecutable semanal" para los testers, o un correo electrónico con el problema específico.

Recuerde que entre más procesos tediosos automatice, más tiempo tendrá para realizar su trabajo.

$Id: Consideraciones.html,v 1.3 2000/02/25 17:10:44 david Exp $