Simulador de Impacto Ganancial
Un software libre desarrollado en Java con Diseño por Contratos
Franco M. Luque
Resumen
En este trabajo se presentan los fundamentos y el desarrollo del Simulador de Impacto Ganancial, un software para el análisis y la planicación de negocios que se enmarca en un proyecto de desarrollo de herramientas para la autogestión del trabajo productivo.
Se propone aplicar el método de construcción de software Orientado a Ob-jetos propuesto por Meyer ([Mey97]) y cristalizado en el lenguaje Eiel y el entorno de desarrollo Eiel Studio, pero trasladado al lenguaje Java y al en-torno de desarrollo NetBeans IDE. La principal innovación respecto del uso tradicional de Java constituye el uso del Diseño por Contratos y el chequeo de aserciones en tiempo de ejecución utilizando el lenguaje JML (Java Modeling Language) y las JML Tools.
Además, se hace la experiencia de combinar e integrar estas herramientas con el uso de la NetBeans Platform, un conjunto de componentes reusables para el desarrollo rápido de aplicaciones de escritorio de look profesional, y del Swing GUI Builder, una herramienta visual para el diseño de interfaces grácas, también utilizada para el desarrollo de prototipos no funcionales para la obtención de requerimientos.
Clasicación:
D.1.5 [Programming Techniques]: Object-oriented Programming;
D.2.2 [Software Engineering]: Design Tools and Techniques Computer-aided software engineering (CASE);
D.2.4 [Software Engineering]: Software/Program Verication Program-ming by contract;
J.1 [Administrative Data Processing]: Business.
Palabras clave: Simulador de Impacto Ganancial, Modelo de Rotación del Capital, Pablo Levín, Bertrand Meyer, Eiel, Diseño por Contratos, Java, JML, Java Modeling Language.
Agradecimientos
A mis viejos, Charo y Fanny, y mis hermanos, Peti y Pau.
A mis compañeros de militancia del Guri y de La Bisagra del 2000 al día de hoy.
A mis mejores amigos, los del colegio y los de la facu.
A los profesores de los buenos, que en Computación son la mayoría. A los compañeros del CEPLAD y de FaSinPat, a quienes espero que les sea de mucha utilidad este trabajo.
Finalmente, y especialmente, a Javier Blanco, por haber propiciado el tra-bajo, y a Martincito Domínguez, por haber sido un excelente director. Ambos, además, buenos profesores, amigos y compañeros.
Prefacio
En la taxonomía clásica de trabajos de tesis, éste entra sin duda en la ca-tegoría de los trabajos aplicados, y dentro del ámbito de la computación, com-partirá estante con trabajos con palabras clave como Ingeniería del software o desarrollo de software. En principio, lucirá orgullosamente su condición de aplicado, lejos de las prestigiosas publicaciones teóricas. Presenta, sin embargo, algunas diferencias importantes, yo diría esenciales, respecto de sus compañeros de especie.
Al margen del desafortunado hecho de no haber cobrado un peso por ha-cer este trabajo (soy sinha-cero y no tan altruista: me hubiera encantado que me paguen), su origen se debe a una inquietud política, un poco individual pe-ro principalmente compartida con muchos docentes y estudiantes, quienes a lo largo de todos estos años hemos puesto en discusión el rol de la Universidad Pública.
Una de las hipótesis que intenta probar este trabajo es que de los proble-mas y necesidades que actualmente tiene nuestra sociedad pueden surgir teproble-mas de investigación y desarrollo de lo más complejos e interesantes. Es, en algún sentido, un objetivo bastante humilde, y representa a lo sumo una pequeña res-puesta a una de las tantas falacias que se escuchan en defensa del status quo del Sistema Cientíco Nacional.
Me pareció importante ensayar una fundamentación del porqué de este pro-yecto, para intentar valorizar su aporte no sólo desde el punto de vista técnico sino también por su aplicabilidad. Es por esto que habrá un capítulo entero dedicado a cuestiones no técnicas.
Vale aclarar que este informe no expresa la totalidad del trabajo realizado, en parte para no hacerlo excesivamente extenso, y en parte porque no tuve tiempo suciente para reejar muchos aspectos. En el sitio [Luq] se encontrará, además del software desarrollado, más información acerca de este trabajo. Espero, en un futuro próximo, poder agregar aún más información útil que todavía no ha sido publicada.
Índice general
I Preliminares
6
1. Introducción 7
1.1. General . . . 7
1.2. Introducción al Proceso de Desarrollo . . . 8
2. Fundamentos del Simulador de Impacto Ganancial 10 2.1. El CEPLAD: Centro de Estudios para la Planicación del Desa-rrollo . . . 10
2.2. El Modelo de Rotación del Capital . . . 11
2.3. El MRC en fórmulas . . . 13
2.4. El Simulador de Impacto Ganancial . . . 14
II El Proceso de Desarrollo
17
3. La construcción de software Orientado a Objetos según Meyer 18 3.1. Introducción (o cómo resumir 1254 páginas) . . . 183.2. Diseño por Contratos . . . 20
3.2.1. Introducción . . . 20
3.2.2. Los elementos del Diseño por Contratos . . . 21
3.2.3. La herencia de los contratos . . . 22
3.2.4. Un cacho de teoría . . . 24
3.3. Exportación Selectiva y Ocultamiento de Información . . . 25
4. Aplicando el método de Meyer en Java 27 4.1. Diseño por Contratos con JML . . . 27
4.1.1. Introducción . . . 27
4.1.2. Algunos elementos de JML . . . 28
4.1.3. Las JML Tools . . . 31
4.1.4. Aplicando el Diseño por Contratos con JML . . . 32
4.2. Exportación Selectiva con JML . . . 34
4.2.1. (des)Niveles de acceso: Java vs. Eiel . . . 34
4.2.2. Un mecanismo de exportación selectiva para Java . . . 35
4.2.3. Usando el nuevo mecanismo . . . 36
4.2.4. Implementación del software necesario . . . 38
4.3. Otros . . . 39
4.3.2. Desarrollo transparente (seamless) e ingeniería de ida y
vuelta . . . 40
4.3.3. Persistencia en Java y convivencia con JML . . . 41
5. Poniendo todo junto, y agregando lo que falta: El Proceso de Desarrollo de Software 46 5.1. El relevamiento y la especicación de los requerimientos del software 46 5.1.1. El Proceso de Requerimientos Volere . . . 46
5.2. Estimación de esfuerzo . . . 48
5.2.1. El método Use Case Points . . . 49
5.3. El ciclo de vida del software . . . 50
5.3.1. Especicación de Requerimientos . . . 50
5.3.2. Diseño . . . 51
5.3.3. Implementación, Testing y Entrega . . . 53
III Desarrollo del Simulador de Impacto Ganancial
54
6. Especicación de Requerimientos 55 6.1. Resumen de las actividades realizadas . . . 556.2. El documento de ERS . . . 56
6.2.1. Alcance del Trabajo . . . 56
6.2.2. Alcance del Producto . . . 57
6.2.3. Stakeholders . . . 57
6.2.4. Requerimientos Funcionales . . . 58
7. Diseño 61 7.1. Arquitectura del Software . . . 61
7.2. El Núcleo del Modelo . . . 62
7.2.1. La clase Aplicacion . . . 62
7.2.2. La clase Negocio . . . 63
7.2.3. La interfaz Archivo . . . 63
7.2.4. La interfaz OperacionIterator . . . 65
7.2.5. Las interfaces Operacion y Categoria . . . 66
7.2.6. Los tipos básicos: Fecha, Monto y Cantidad . . . 67
7.2.7. Los Escenarios . . . 69
7.2.8. Las utilidades OperacionCache y OperacionMerger . . . 71
7.2.9. La interfaz Cambio . . . 73
7.2.10. El Modelo de Rotación del Capital . . . 74
8. Implementación, Testing y Entrega 77 8.1. Planicación . . . 77
8.2. Implementación . . . 78
8.3. Testing . . . 78
8.4. Entrega . . . 79
IV Conclusiones y trabajos futuros
80
10.Conclusiones 82
10.1. Acerca del Proceso de Desarrollo . . . 82
10.1.1. Los requerimientos . . . 83
10.1.2. El Diseño . . . 83
10.1.3. Implementación . . . 84
10.1.4. Testing . . . 84
10.1.5. Diseño por Contratos . . . 85
10.2. Acerca el Simulador de Impacto Ganancial . . . 86
10.2.1. El SIG vs. el YSI . . . 86 10.3. Recapitulando . . . 87 11.Trabajos futuros 89
V Apéndices
90
A. Preproyecto de Tesis 91 A.1. Resumen . . . 91A.1.1. Materias Correlativas . . . 91
A.1.2. Contexto . . . 91
A.1.3. Objetivo . . . 92
A.1.4. Plan de trabajo . . . 93
B. Documentos de la Ingeniería del Software del SIG 94 B.1. Reuniones . . . 94 B.1.1. Reunión del 21/06/2006 . . . 94 B.1.2. Reunión del 22/06/2006 . . . 95 B.1.3. Reunión del 12/07/2006 . . . 96 B.1.4. Reunión del 20/09/2006 . . . 97 C. Bugs resueltos 100
Parte I
Capítulo 1
Introducción
1.1. General
La realización de esta tesis fue, en cierta forma, dos trabajos al mismo tiem-po. Por un lado, se trató del desarrollo de una aplicación de software, el Simu-lador de Impacto Ganancial, o SIG. Por otro, se trató del estudio de técnicas y metodologías de desarrollo de software, y de la enunciación y utilización de un Proceso de Desarrollo derivado de éstas.
El software, con toda la documentación que lo acompaña, es una aplicación concreta de software libre para el uso como herramienta de análisis y plani-cación de negocios. Los fundamentos y los requerimientos principales del SIG tienen su origen en el CEPLAD, un grupo de investigación en Economía de la Universidad de Buenos Aires, principal destinatario del software.
Por otra parte, el Proceso de Desarrollo confeccionado, que se encuentra materializado en este informe, representa un aporte a la comunidad informática ya que puede ser reutilizado en cualquier otro proyecto de desarrollo de software que guarde características similares. En esencia, se trata de la traslación al lenguaje Java de los elementos más importantes del método Orientado a Objetos de Meyer presentado en [Mey97], principalmente el Diseño por Contratos, y por lo tanto no se presentan ideas teóricas originales. Salvo pequeñas partes, tampoco se trata del desarrollo de herramientas de software para consumar esta traslación, sino de la conjunción e integración de herramientas existentes, todas ellas de software libre.
Muchas de las partes que componen este informe están escritas con la inten-ción de que puedan ser leídas por separado. En estas partes serán señalados los conocimientos previos necesarios y, de existir, las dependencias con otras partes del trabajo. Ocasionalmente se encontrarán algunas redundancias.
Este informe se encuentra organizado de la siguiente manera:
En lo que resta de la Introducción, la sección 1.2 es un resumen de las carac-terísticas del Proceso de Desarrollo. La Parte I se completa con el Capítulo 2, que describe las motivaciones y los principios teóricos de funcionamiento del Simulador de Impacto Ganancial.
La Parte II contiene la teoría y la denición del Proceso de Desarrollo. El Capítulo 3 es una exposición del método Orientado a Objetos de Meyer, y por lo tanto un resumen de [Mey97], aunque con una leve tendencia a dar
mayor importancia a los temas que convienen a este trabajo. El Capítulo 4 se reere a la aplicación en tecnología Java de los elementos del capítulo previo. Finalmente, el Capítulo 5 integra las distintas propuestas y completa el cuadro con los aspectos faltantes que denen el Proceso.
La Parte III se reere al desarrollo del Simulador de Impacto Ganancial. Los capítulos que la componen se reeren a las distintas etapas ejecutadas, relatando la experiencia de aplicación del Proceso y explicando los productos intermedios obtenidos.
La Parte IV y última presenta las conclusiones del trabajo y los trabajos futuros que éste posibilita. También hace una breve reseña de algunos trabajos relacionados. Se reere tanto al Simulador de Impacto Ganancial como a los resultados generales de la aplicación del Proceso.
1.2. Introducción al Proceso de Desarrollo
El Proceso de Desarrollo que propongo utilizar tiene como objetivo principal la producción de software de calidad con el mínimo esfuerzo posible. Para lograr esto, el Proceso estará centrado en el uso intensivo de herramientas y librerías reusables. De esta manera se pretende minimizar el trabajo repetitivo y al mismo tiempo aprovechar las cualidades de software muy evolucionado.
La elección del lenguaje de programación no es entonces una mera incum-bencia de implementación, si no que inuye decisivamente en todo el Proceso de Desarrollo. El Proceso propuesto está basado en tecnología Java, cosa que pone a nuestra disposición un sinnúmero de herramientas, librerías y documentación para ser utilizados a lo largo de todas las etapas del proyecto. Además, provee una plataforma, la máquina virtual Java, que independiza al software de toda dependencia de un sistema operativo o hardware en particular.
Para la concresión de los objetivos planteados, por supuesto, no es suciente la reutilización, ya que se deben asegurar las cualidades deseadas también en los módulos producidos en el proyecto. En este marco es que se propone uti-lizar el método de construcción de software presentado por Meyer en su libro Object Oriented Software Construction, 2nd Edition ([Mey97]). El autor tam-bién dene un lenguaje que permite la aplicación del método, Eiel, que tiene características muy diferentes a las del lenguaje Java.
Uno de los objetivos de este trabajo es ver en qué medida se pueden aplicar los distintos aspectos del método de Meyer en un entorno de desarrollo en el que se utilice la tecnología Java. Algunos elementos serán facilmente utilizables, por estar incorporados al lenguaje Java, otros serán prácticamente imposibles, como la herencia múltiple, y otros dependerán de la existencia de herramientas adecuadas, como es el caso del Diseño por Contratos.
El Diseño por Contratos es un método propuesto por Meyer, e inspirado en las ternas de Hoare, para la especicación del comportamiento de módulos de software. Básicamente, permite escribir distintos tipos de aserciones, principal-mente invariantes de clase y precondiciones y postcondiciones de métodos.
Una hipótesis que intento probar en este trabajo es que el uso de un Proceso que incorpore el Diseño por Contratos representa una opción práctica y conve-niente en el contexto del desarrollo sobre tecnología Java. Requisito obligatorio para el éxito de esta hipótesis es la disponibilidad de herramientas de softwa-re apropiadas. Surge, prácticamente como única opción potable, el lenguaje de
especicación JML, Java Modeling Language, y las JML Tools, que proveen, entre otras cosas, un compilador de Java que incorpora el chequeo de aserciones en tiempo de ejecución.
Otro elemento del método de Meyer al que se le prestará particular atención es el mecanismo de Exportación Selectiva. La Exportación Selectiva permite especicar niveles de acceso para las característicias de una clase de una forma mucho más general que la provista por el lenguaje Java. El marco de este trabajo, se desarrolló en un pequeño módulo reusable que permite la expresión en Java de la Exportación Selectiva a través de JML.
Para el diseño del software, Meyer propone la utilización del mismo lenguaje Eiel y de una notación gráca para éste, Business Object Notation (BON), que en nuestro Proceso será sustituído por UML. Meyer propone, además, el desarrollo seamless, que asegura una sincronización permanente del diseño con la implementación, y para el que se necesita una herramienta de diseño que lo implemente. En el marco de Java, se utilizará una versión limitada del desarrollo seamless, denominada ingeniería de ida y vuelta, y que se logrará gracias al uso del módulo UML para NetBeans.
En [Mey97] también se señala la importancia de contar con un entorno de desarrollo integrado y con una herramienta de construcción de interfaces grácas que den soporte al método. En este trabajo se propone la utilización de NetBeans IDE, que es un entorno que provee además de una herramienta muy evolucionada de diseño de GUIs, Swing GUI Builder.
Ya al margen del método de Meyer, en Java se puede ir aún más lejos en reutilización gracias a la disponibilidad de las denominadas Rich Client Plat-forms, en el caso de este trabajo NetBeans Platform. Esta plataforma provee una aplicación de escritorio genérica y un conjunto de módulos que capturan las necesidades comunes a todas las aplicaciones de escritorio avanzadas.
Otra de las particularidades de este proyecto es que los requerimientos del software serán denidos por una organización externa al equipo de desarrollo (por no decir yo mismo). El Proceso de Desarrollo se completará, entonces, con una etapa de especicación de requerimientos en la que se aplicará una versión simplicada del Proceso de Requerimientos Volere propuesto en [RR06]. Se utilizará, además, una técnica de estimación de costos en base a los casos de uso, denominada Use Case Points y propuesta en [Kar93].
Capítulo 2
Fundamentos del Simulador
de Impacto Ganancial
Esta sección representa una pequeña intromisión en la disciplina económica, sobre todo en la Economía Política, lo suciente como para entender las moti-vaciones de la realización del software y los principios de su funcionamiento. La falta de mayor profundidad no se debe al poco interés que merezca el tema si no, por una parte, al hecho de que queda por fuera de los objetivos de este tra-bajo, y por otra, a la falta de autoridad para desarrollarlo correctamente. Para un tratamiento idóneo debe recurrirse a las referencias citadas en esta parte, [LK99], [Lev05], [Lev06] y [Lev97].
Dada la precaria formación en economía y contabilidad que el autor de es-te resumen oses-tenta, un conocedor del es-tema puede esperar encontrar muchas imprecisiones y un grosero e irresponsable uso de la terminología. A modo de compensación, se realizarán grandes esfuerzos didácticos y a la hora de las de-niciones se usará un rigor matemático.
2.1. El CEPLAD: Centro de Estudios para la
Pla-nicación del Desarrollo
El CEPLAD es un grupo de investigación perteneciente al Instituto de Inves-tigaciones Económicas de la Facultad de Ciencias Económicas de la Universidad de Buenos Aires. Su director, el Dr. Pablo Levín, cuenta con numerosas publica-ciones en Economía, principalmente en Economía Política, y es autor del libro El Capital Tecnológico, [Lev97], por el cual recibió recientemente el Primer Premio Nacional de Economía.
El sustantivo en torno al que giran todos los objetivos del CEPLAD es el de la planicación económica, siendo el primario de ellos dar a conocer que la planicación económica es una exigencia racional aplicable a todas las decisiones económicas tanto de índole privada como de naturaleza pública ([CEP]).
El Modelo de Rotación del Capital y el diseño del Simulador de Impacto Ganancial son herramientas teóricas y prácticas desarrolladas en pos de este objetivo. Los fundamentos de ambos se encuentran expuestos en [LK99], a donde también se presenta una implementación prototípica del SIG, denominada YSI.
La implementación realizada en este trabajo apunta a ser la versión denitiva del SIG, y en parte por eso es que ha sido bautizada con el mismo nombre que la idea en abstracto1.
La formación y adquisición de experiencia en plancación por parte de la clase trabajadora ha sido señalada por Levín como un elemento estratégico pri-mordial en el camino hacia la emancipación económica. En [Lev05], analiza el rol del planicador a lo largo de la historia, para arribar a una caracterización propia del sistema capitalista actual y de las relaciones de poder entre los dis-tintos tipos de planicadores, sentando las bases teóricas para el desarrollo de una estrategia para el cambio social. Por otra parte, en [Lev06], el mismo au-tor explicita la estrategia propuesta y su adaptación a las particularidades del sistema productivo argentino.
En este sentido, el Simulador de Impacto Ganancial también apunta a ser una herramienta utilizada por grupos de trabajadores, incluso en el caso en que éstos no tengan el control de los medios de producción. Levín se reere, en este caso, a la práctica de la contra-planicación: [. . . ] cuando [los trabajadores] auditan o scalizan las políticas comerciales y los manejos nancieros de la empresa, cuando ejercen vigilancia sobre las maniobras de estafa y vaciamiento que pueden dejarlos sin trabajo [. . . ] ([Lev06]).
Más importante aún es la planicación en una empresa controlada por sus trabajadores, y sobre todo en aquellas con mayor potencial productivo y econó-mico. Y en esta situación la planicación debe ser complementada y articulada con un sistema que contemple los mecanismos democráticos de toma de deci-sión, que denen tanto las metas de la empresa como los mandatos que cada trabajador debe cumplir. En el caso de las empresas recuperadas, también se deben realizar tareas de relevamiento e informatización de la información, pa-ra reconstruir los libros de la empresa, utilizando sistemas adaptados a las necesidades particulares del control obrero.
Todas estas necesidades han sido consideradas por el CEPLAD en su proyec-to SIPLAM, Soporte Informático del Plan de Metas, que propone la elaboración de un sistema informático para la administración de las metas de una empresa autogestionada. Este proyecto, que todavía se encuentra en una etapa prelimi-nar, ha sido concebido para ser implementado en el sector Porcellanato de la Cooperativa de Trabajadores Ceramistas Fasinpat (ex Zanón) de Neuquén, y el Simulador de Impacto Ganancial constituye una de sus partes.
2.2. El Modelo de Rotación del Capital
En la contabilidad tradicional existen muchos indicadores de rentabilidad, tan conocidos y difundidos que son utilizados en casi todas las empresas y al-gunos de ellos se enseñan directamente en el nivel medio. En [LK99] podemos encontrar una breve descripción de los más populares:
El criterio de la tasa interna de retorno, el criterio del valor actual neto,
el período de recuperación de la inversión,
1En parte porque no se nos ocurrió otro nombre mejor. No descarto un rebautismo en el
Mes Egresos Ingresos E 100 110 F 100 110 M 100 110 A 100 110 M 100 110 J 100 110 J 100 110 A 100 110 S 100 110 O 100 110 N 100 110 D 100 110
Cuadro 2.1: Cronoestructura elemental de ejemplo. la tasa de retorno contable
y la razón benecio - costo.
Además, en el artículo citado se exponen las falencias de estos indicadores y sus desventajas respecto de un nuevo modelo, el Modelo de Rotación del Capital, que tiene sus propios indicadores de rentabilidad.
El Modelo de Rotación del Capital ha sido desarrollado originalmente por Pa-blo Levín, y actualmente es objeto de uso y estudio por parte de los integrantes del CEPLAD. Describe a la empresa en base al conjunto de operaciones fecha-das que ésta realiza dentro de un período de tiempo que se desea analizar. Las operaciones se reeren, por ejemplo, a compras o ventas de productos, o al pago de servicios o sueldos. A esta información se la denomina cronoestructura, y puede ser elaborada manualmente o deducida de los archivos informatizados de una empresa, como ser Facturación, Compras, Sueldos y Activo Fijo.
El Modelo propone una nueva forma de calcular la tasa de ganancia, como el cociente entre la masa de ganancia y el capital total necesario. La masa de ganancia no es otra cosa que la diferencia entre el ingreso total y el egreso total. Éstos, a su vez, se denen como la suma de los montos involucrados en cada operación de ingreso y de egreso, respectivamente. En criollo, toda la plata que entra y toda la plata que sale.
La tasa de ganancia tradicional, muy intuitivamente, se dene como el cociente entre la masa de ganancia y el egreso total. Aquí es donde reside una de las principales innovaciones del Modelo, cuya tasa de ganancia se computa con un denominador diferente, el capital total necesario, que se encuentra denido en [LK99] como la suma entre el capital jo y el capital circulante.
Sin embargo, en este trabajo utilizaremos una versión simplicada del Mo-delo que no considerará la intervención del capital jo, por lo que sólo hace falta denir el capital circulante, que, a diferencia del egreso total, no es lo que uno gasta sino la plata que uno necesita para afrontar esos gastos, que es algo muy diferente, ya que muchos de los gastos pueden ser afrontados con ingresos previos generados por la dinámica del negocio en estudio.
[LK99] se vale de un ejemplo elemental y muy efectivo para ilustrar este concepto, que se puede ver en el Cuadro 2.1. Puede suponerse que la
cronoes-tructura corresponde a un negocio en el que todos los meses se realiza una compra por el valor de 100 en mercadería para luego ser vendida a 110. En este ejemplo, el egreso total es de 1200 y el ingreso total de 1320, por lo que la masa de ganancia es de 1320 − 1200 = 120 y tasa de ganancia tradicional vale 120/1200 = 0,1 = 10 %. Sin embargo, para llevar adelante este negocio sólo se necesita un desembolso de 100 en el primer período, enero, ya que el resto de los egresos puede ser afrontado con las ganancias obtenidas previamente. El capital circulante es, entonces, de 100, y la tasa de ganancia vale 120/100 = 1,2 = 120 %. Si la mercadería hubiera sido comprada toda en enero el uso de la tasa de ga-nancia tradicional no nos habría permitido apreciar la diferencia, mientras que el Modelo de Rotación del Capital sí, ya que el capital circulante hubiera sido de 1200 y la tasa de ganancia hubiera valido 120/1200 = 0,1 = 10 %.
Una forma de obtener el capital circulante es calculando los fondos dispo-nibles en el momento de cada egreso, esto es, la plata con la que se cuenta para afrontar ese egreso. El adelanto de capital es la plata que falta para poder cubrir el egreso, y la suma de todos los adelantos de capital no es otra cosa que el capital circulante.
Otra variable de interés para el Modelo en su versión simplicada es la velocidad de rotación del capital, que se dene como el cociente entre el egreso total y el capital circulante. En el ejemplo vale 1200/100 = 12.
2.3. El MRC en fórmulas
Para el lector desinteresado en las connotaciones económicas del Modelo de Rotación del Capital pero acionado a la lectura de fórmulas será suciente la lectura de esta sección. Las deniciones aquí presentadas son exactamente las implementadas en la versión actual del Simulador de Impacto Ganancial.
Partiremos de suponer que se cuenta con una lista de operaciones fechadas de egresos e ingresos, todas comprendidas dentro de un período de registro. El primer paso para poder utilizar el Modelo es confeccionar la cronoestructura, para lo que se divide el período de registro en N subperíodos, que no nece-sariamente deben ser de igual tamaño. Luego se calcula, para cada período i,
egreso(i)e ingreso(i) como la suma de los montos involucrados en operaciones de egreso e ingreso, respectivamente, dentro de ese período.
La división del período de registro elegida se denomina criterio de agrega-ción de la cronoestructura. Dentro de cada subperíodo se pierde la informaagrega-ción del orden temporal de las operaciones, por lo que su tamaño inuye en la ca-lidad de los resultados obtenidos. En el extremo de máxima granularidad se puede denir un subperíodo por fecha en la que haya al menos una operación, en cuyo caso no hay pérdida alguna de información.
Una vez denidos egreso(i) e ingreso(i) podemos formalizar fácilmente las primeras deniciones, que no son exclusivas del Modelo de Rotación del Capital:
egresoT otal = N X i=1 egreso(i) (2.1) ingresoT otal = N X i=1 ingreso(i) (2.2)
masaGanancia = ingresoT otal − egresoT otal (2.3)
tasaGananciaT radicional = masaGanancia
egresoT otal (2.4)
Para denir los principales indicadores del Modelo, primero debemos for-malizar la denición de los dos vectores de valores mencionados en la sección anterior, que permiten calcular el capital circulante. Por una parte, el fondo disponible para el i-ésimo período es
f ondo(1) = 0
f ondo(i + 1) = m´ax(f ondo(i) − egreso(i), 0) (2.5) y el adelanto de capital para el i-ésimo período, es, como decíamos, la plata necesaria para afrontar el i-ésimo egreso, o sea
adelanto(i) = m´ax(egreso(i) − f ondo(i), 0) (2.6) Luego, el capital circulante es la suma de los adelantos de capital,
capitalCirculante = N X i=1
adelanto(i) (2.7)
y, para terminar la formalización, los dos últimos indicadores:
tasaGanancia = masaGanancia
capitalCirculante (2.8)
velocidadRotacion = egresoT otal
capitalCirculante (2.9)
2.4. El Simulador de Impacto Ganancial
El hecho que le da sentido práctico al Modelo de Rotación del Capital es la existencia de tecnología suciente como para permitir fácilmente calcular sus in-dicadores asociados, que llamaremos resultados de la empresa. El Simulador de Impacto Ganancial implementa esta funcionalidad, pero las posibilidades del SIG van mucho más allá gracias a una armación muy importante de [LK99]:
Todo factor que incide en el rendimiento del capital, se expresa en una cro-noestructura o en un conjunto de cambios (de efectos no compensados) sobre la cronoestructura dada. Así ocurrirá con cualquier variación en la conguración de los precios de los insumos y/o los productos, en las convenciones o modali-dades comerciales y nancieras, en la presión y la estructura tributaria, en la mezcla de procesos y productos, en la organización, en la tecnología, en la pro-ductividad material. La dirección, el sentido y la intensidad del impacto de esas variaciones en el sendero de acumulación asequible a la empresa dependerán de cómo transforman la cronoestructura.
De esta manera, todos los escenarios que el planicador desee analizar y comparar podrán ser obtenidos a través de la introducción de cambios en la cronoestructura. Incluso aquellos en los que se deseen considerar aspectos o áreas del negocio por separado, o en los que se quiera evaluar la rentabilidad de un potencial negocio.
El SIG permite al usuario denir archivos que contienen listas de opera-ciones de diversos orígenes2, y luego denir escenarios base en los que se seleccionarán los archivos que compondrán la cronoestructura base. Un esce-nario base puede referirse a una parte del negocio que se quiera analizar por separado, o incorporar todos los archivos de la empresa, y constituye el punto de partida a partir del cuál se podrán evaluar escenarios alternativos.
Todo es, a partir de ahí, agregar, modicar o quitar operaciones a la cro-noestructura base. Sin embargo, para preservar el escenario base y así permitir comparar sus resultados con de los resultantes de los cambios introducidos, el SIG incorpora la noción del subescenario. Un subescenario es un escenario en el que se pueden denir cambios puntuales, y su cronoestructura asociada se-rá la resultante de aplicar estos cambios sobre la del escenario padre, que puede ser tanto un escenario base como otro subescenario. Así, un escenario base es la raíz de un árbol de escenarios, a donde cada nodo tiene una cronoestructura asociada y por lo tanto sus propios resultados de la empresa.
Claro que las posibles modicaciones que se pueden realizar pueden ser tan arbitrarias como uno quiera, y muchas de ellas no tienen correlato con un escena-rio posible. El Simulador de Impacto Ganancial provee un conjunto de cambios posibles, algunos más abstractos con los que se puede lograr una variedad muy grande de resultados, y otros más especícos que se identican con algunos esce-narios que suelen ser interesantes en la práctica. Cada área de negocios tendrá sus propias necesidades de simulación, por lo que se espera que el conjunto de cambio ofrecidos por el SIG deba ser extendido en el futuro, y de hecho el software ha sido diseñado contemplando esta posibilidad.
El SIG también contempla la posibilidad de agregar a la cronoestructura partes que no provengan de los archivos reales de la empresa, o incluso armar una cronoestructura completamente cticia. Si bien el usuario podría lograr es-to escribiendo a mano la lista de operaciones en una planilla de cálculo y luego importándola en el Simulador, desde el CEPLAD se ha señalado que la confec-ción manual de cronoestructuras coherentes y a la vez interesantes es una tarea extremadamente complicada. A través del reconocimiento de ciertos patrones comunes en las cronoestructuras, se puede reducir drásticamente la cantidad de información que el usuario debe proveer, y dejar la tarea de generar la lista ex-plícita de operaciones, denominada archivo generado, al Simulador. Algunos de estos patrones pueden ser deducidos de las formas de información estadística que existen en contabilidad y que tienen una cronoestructura implícita asociada. Un patrón reconocido gracias a uno de los ejemplos provistos por el CE-PLAD es el de la estacionalidad mensual, semanal y diaria de un conjunto de operaciones dentro de un período de registro de un año. En un informe de ven-ta anual de cierto producto de un comercio, por ejemplo, puede encontrarse la siguiente información: monto total de ventas en el año, distribución mensual de las ventas, distrubución semanal (se supone que es la misma para todos los meses) y distribución por día de la semana (suponiendo que es la misma todas las semanas del año) (Cuadro 2.2). Esta información es suciente para generar una cronoestructura con, a lo sumo, 365 operaciones de egreso, una por día del año. En el ejemplo, el monto del egreso para el día martes 17 de octubre de 2006
2La versión actual del SIG sólo permite obtener operaciones de planillas de cálculo. El
CEPLAD ha considerado de suma importancia la lectura de bases de datos de los sistemas de gestión (denominados ERPs, Enterprise Resource Planning) de uso difundido en las empresas, y se espera poder incorporarlo en las próximas versiones del software.
Año Monto total 2006 $ 700.000 Mes % Enero 6,2 % Febrero 7,1 % Marzo 9,5 % Abril 7,9 % Mayo 8,0 % Junio 8,1 % Julio 9,6 % Agosto 8,4 % Septiembre 8,4 % Octubre 9,0 % Noviembre 8,1 % Diciembre 9,7 % Semana % 1ra 25 % 2da 28 % 3ra 22 % 4ta 25 % Día % Lunes 20 % Martes 20 % Miércoles 20 % Jueves 20 % Viernes 20 % Sábado 0 % Domingo 0 %
Cuadro 2.2: Ejemplo de información estadística para generar operaciones cti-cias.
sería $700000 × 9, 0 % × 22 % × 20 % = $2772.
El SIG provee una implementación de este patrón3, y su diseño está prepa-rado para agregar soporte para nuevos patrones a medida que se vayan recono-ciendo. Como en el caso de los cambios, es posible que cada tipo de empresa tenga sus propios patrones, y esta funcionalidad también puede resultar útil para el uso del Simulador como herramienta de control paralelo por parte de los trabajadores, en cuyo caso éstos no cuentan con los archivos de la empresa pero pueden estimarlos a través de otras fuentes de información.
3Si bien en la versión presentada en este trabajo no presenta esta funcionalidad, se
Parte II
Capítulo 3
La construcción de software
Orientado a Objetos según
Meyer
En el tercer año de la carrera, junto con mis amigos y compañeros de estu-dio de ese momento, descubrimos este libro de Bertrand Meyer llamado Ob-ject Oriented Software Construction Second Edition (el incansablemente citado [Mey97]) y el lenguaje Eiel. Inmediatamente nos llamó la atención y no tardó en despertarnos cierto fanatismo religioso, principalmente producto del perl de nuestra formación, y no dudo que surtió y surtirá el mismo efecto en muchos otros estudiantes. Sin embargo nuestra experiencia no fue mucho mas allá de un conocimiento limitado del lenguaje, y nuestras exigencias tampoco eran mu-chas: teníamos un lenguaje a dónde podíamos descargar tantas precondiciones, postcondiciones, invariantes y funciones de cota reprimidas durante años.
El lector podrá ver que la propuesta de Meyer va mucho más allá de estas cosas. En la próxima sección se desarrollará un pequeño resumen de las ideas más innovadoras propuestas en [Mey97], y en las subsiguientes se tratarán con mayor profundidad aquellos temas que han adquirido mayor relevancia en este trabajo.
Será imprescindible para el lector tener conocimiento de las características generales de los lenguajes orientados a objetos.
3.1. Introducción (o cómo resumir 1254 páginas)
Meyer realiza un estudio completo que parte de la denición de lo que se considera la calidad del software, y a través de una discusión metodológica va construyendo un lenguaje que es a la vez un método, y deniendo cuáles son las herramientas y librerías1 de software necesarias y factibles para poder llevarlo a cabo.
Comienza arribando a la conclusión de que, para el desarrollo de software con las cualidades deseadas, siendo la reusabilidad la principal de ellas, la descomposición modular más apropiada es la orientada al reconocimiento de
los diferentes Tipos Abstractos de Datos involucrados en el sistema. Según Meyer, las clases no son otra cosa que implementaciones de TADs2.
El lenguaje-método construido es, entonces, un lenguaje perteneciente al pa-radigma orientado a objetos, y por lo tanto comparte todas las características generales que denen a éste paradigma. Tanto del análsis teórico como de la ex-periencia se desprenden los mecanismos que el autor considera necesarios para enriquecer el lenguaje: exportación selectiva, genericidad, diseño por con-tratos, manejo de excepciones y herencia múltiple, los más importantes, y los que lo identican y distinguen del resto de los lenguajes O-O.
En [Mey97] se presentan elementos de un Proceso de Desarrollo propio y bastante alejado de los utilizados en la Ingeniería del Software tradicional. Si bien no se desarrollan técnicas para la obtención de requerimientos, sino que asume la existencia de documentos que los especican, ni tampoco se explaya en las cuestiones de management, Meyer se reere al ciclo de vida del software, un elemento central en cualquier Proceso. La principal conclusión a la que arriba Meyer en este aspecto es que las etapas de análisis, diseño e implementación se encuentran regidas por un mismo método, salvo que con distintos niveles de abstracción, y por lo tanto el mismo lenguaje es apropiado para ser utilizado en todas éstas etapas.
Yendo un poco más allá, el modelo de ciclo de vida del software que propo-ne es el de estalactita (Figura 3.1), en el que, si bien hay un orden temporal primario en el que se ejecutan las etapas, el desarrollo se realiza siempre sobre un mismo modelo orientado a objetos, salvo que con vistas con distintos nive-les de abstracción. Meyer propone el uso de la notación BON, Business Object Notation, para el diseño de vistas grácas, por lo que también se plantea la ne-cesidad de contar con un entorno de desarrollo que garantize la conexión de los diagramas con el modelo subyacente. Esto se denomina desarrollo seamless o transparente3. Más allá aún, el autor plantea como un hecho inherente al desarrollo de software el surgimiento de la necesidad o la conveniencia de rea-lizar cambios sobre etapas anteriores, y el soporte para este tipo de cambios, denominado reversibilidad, también se encuentra garantizado por el desarrollo
2Implementaciones que pueden ser parciales, para el caso de las clases abstractas, o
dife-ridas (deferred) en la terminología de [Mey97].
3Traducción mía, un poco arbitraria. Es más claro que hablar de desarrollo inconsútil o
sin costuras, que es la traducción de diccionario.
Figura 3.1: El ciclo de vida del software de acuerdo al modelo de estalactita. Fuente: [Mey97], pág. 925.
seamless.
En cuanto a la aplicación del método, Meyer arma que, por supuesto, el mero uso del lenguaje no es una garantía de éxito, y desarrolla una metodología4 para favorecer la obtención de diseños de calidad a partir de la especicación de requerimientos. El reconocimiento de estructuras arquitecturales de uso común y la reutilización de Patrones de Diseño en estos casos representa un método clave, y se encuentra ilustrado en [Mey97] con numerosos ejemplos.
Meyer revela al nal de su libro que el lenguaje construido ya existe y se llama Eiel, y presenta un producto integrado desarrollado por la empresa ISE Inc., Interactive Software Engineering, fundada por el mismo Meyer. Se compone de un compilador del lenguaje, un entorno de desarrollo con todas las caracte-rísticas deseables, Eiel Studio, y un conjunto de librerías que completan los requerimientos del método.5
3.2. Diseño por Contratos
3.2.1. Introducción
El Diseño por Contratos o Design by Contract es, sin lugar a dudas, el aporte más importante realizado por Bertrand Meyer y su lenguaje Eiel a la metodología Orientada a Objetos.6Se trata, básicamente, de la introducción de diferentes tipos de aserciones que permiten especicar el comportamiento de las clases y chequear su cumplimiento en tiempo de ejecución, y cuya semántica está dada por ternas de Hoare.
Las ventajas del uso del Diseño por Contratos, de acuerdo a [Mey97] (pág. 334), son:
Ayuda a producir software correcto desde el comienzo porque está diseñado para ser correcto.
Ayuda a lograr un mejor entendimiento del problema y sus eventuales soluciones, y detectar tempranamente fallas en el diseño.
Facilita la tarea de documentación del software.
Provee una base para hacer testing y debugging sistemáticos: la violación de una aserción en tiempo de ejecución es la manifestación de un bug en el software.
La especicación de un módulo dene en qué condiciones debe ser utilizado y qué resultados garantiza. Es en este sentido que las aserciones obran como un contrato entre el módulo y los otros módulos que deseen ser sus clientes.7
4Por supuesto que siempre nos referimos a la metodología como el estudio de los métodos. 5Como si se tratara de un programa televisivo de cocina, en la parte nal de su libro Meyer
saca del horno el producto ya cocinado y listo para ser servido.
6Valga como pequeña prueba de esto que, al día de la fecha, el Diseño por Contratos es
el request for enhancement (RFE) para Java más votado en http://bugs.sun.com/ (Bug ID 4449383: Support For 'Design by Contract', beyond a simple assertion facility).
3.2.2. Los elementos del Diseño por Contratos
Meyer enriquece el lenguaje Eiel con los siguientes tipos de aserción: Precondiciones y postcondiciones de rutinas (ya sean métodos o construc-tores).
Invariantes de clase. Aserciones de código.
Invariantes y variantes de ciclos. Precondiciones
La precondición de una rutina es una aserción que debe cumplirse cada vez que la rutina sea invocada, y por lo general establece propiedades que deben cumplir los parámetros. La violación de una precondición en tiempo de ejecución es un error cometido por la rutina invocadora, y por lo tanto la manifestación de un bug en el módulo cliente.
Como los clientes que deseen invocar una rutina deben antes satisfacer su precondición, éstos deben tener la posibilidad de asegurarla. Es por esto que todos los features8 mencionados en la precondición de una rutina deben ser accesibles por los clientes que pueden invocarla (ver la sección 3.3 acerca de la exportación selectiva).
Postcondiciones
La postcondición establece las propiedades que una rutina debe garantizar una vez nalizada su ejecución, y suele referirse al estado del objeto y también al valor devuelto en caso de que se devuelva alguno. La violación de la postcon-dición de una rutina en tiempo de ejecución es la manifestación de un bug en el módulo que provee la rutina.
Las aserciones de una postcondición pueden caracterizar el estado nal en función del estado del objeto al iniciarse la ejecución de la rutina. Para esto se cuenta con la notación old e , que representa el valor de la expresión e en el estado inicial. Para referirse al valor devuelto por la rutina, se utiliza Result, la misma entidad que se utiliza en el cuerpo de la rutina.
Las funciones mencionadas en una postcondición no necesariamente deben ser visibles por los clientes de la rutina. Algunas aserciones de la postcondi-ción pueden referirse a propiedades no directamente utilizables por los clientes. Aquellas aserciones que se reeran sólo a características secretas no formarán parte de la interfaz de la rutina y por lo tanto no gurarán en el contrato de la clase.
Invariantes de clase
El invariante de clase es una aserción que debe cumplirse en todo estado visible9 de las instancias de la clase. Por lo tanto, para empezar, todos los
8Los features de una clase son los atributos, métodos y constructores que ésta declara. 9Un estado visible es un estado en el que el objeto no se encuentra ejecutando ninguna
constructores deben asegurar que se cumpla al nalizar su ejecución. Además, todas las rutinas exportadas pueden asumir que se cumple cuando son invocadas. Estas rutinas pueden violar el invariante en el transcurso de su ejecución, ya que estos estados intermedios no son visibles, pero deben satisfacerlo al terminar. En este sentido, puede decirse que el invariante de clase es implícitamente parte de la precondición y la postcondición de todas las rutinas exportadas de la clase. Las rutinas no exportadas, por otra parte, no tendrán relación con el inva-riante: ni podrán asumirlo ni deberán preservarlo. Este se debe a que sólo serán invocadas por otras rutinas del mismo objeto.
El invariante de una clase será chequeado siempre al nalizar la ejecución de cualquier constructor o método. Así como con las postcondiciones, la violación de un invariante en este punto será la manifestación de un bug en el módulo. Sor-prendentemente, veremos que también será necesario chequear el cumplimiento de los invariantes a la entrada de las rutinas.
No será suciente para asegurar la correctitud de un invariante el hecho de que las rutinas de la clase lo preserven. El invariante de un objeto por lo general expresará propiedades de los objetos que tiene referenciados. Un cambio de estado en alguno de esos objetos podrá invalidar el invariante, y esto habrá ocurrido sin haber invocado ningún método del objeto. Esto signica que el invariante podría no cumplirse al incio de la siguiente ejecución de un método de este objeto, y de ahí la necesidad de chequearlo en este punto.
Este problema se denomina Efecto Indirecto de Invariante (Indirect In-variant Eect), y en la práctica es un fenómeno muy común, ya que por lo general para expresar invariantes útiles siempre se deberá hablar del estado de otros objetos.
Algunas partes del invariante de clase pueden referirse sólo a features secre-tos de la clase, por ejemplo para expresar propiedades de consistencia de los atributos que componen la clase. Estas partes del invariante se denominan in-variante de implementación, y no forman parte del contrato de una clase ya que no son externamente visibles.
Aserciones de código e invariantes y variantes de ciclos
Las aserciones de código y los invariantes y variantes de ciclos son mecanismos que permiten especicar propiedades que se cumplirán en ciertos puntos de la ejecución de una rutina. Se encuentran explicados en [Mey97] (págs. 378-388), pero son intuitivos para el lector que conozca las ternas de Hoare. Como sólo aparecen en la implementación, no son estrictamente parte del Diseño por Contratos. Sirven para documentar propiedades que se suponen correctas pero que no se pueden deducir claramente del contexto. El chequeo en tiempo de ejecución permite detectar los casos en que estas suposiciones hayan sido equivocadas.
3.2.3. La herencia de los contratos
A la hora de utilizar la herencia surge el interrogante de cómo conjugar el contrato de una clase con los de las clases heredadas (recordemos que Eiel tiene herencia múltiple). Para los invariantes de clase la respuesta es muy sencilla: los invariantes de todas las clases heredadas se aplican también a la misma clase.
Los contratos de las rutinas que no se redenen en la clase también se heredan sin mayores problemas.
La complicación surge a la hora de la redeclaración de una rutina, que tendrá una de las siguientes formas:
Redenición de una rutina que ya se encuentra implementada. Implementación de una rutina diferida.10
Redeclaración de una función que no toma parámetros como un atributo.11 En todos los casos la solución debe garantizar la siguiente regla: la redeclara-ción de una rutina sólo puede debilitar la precondiredeclara-ción y fortalecer la postcondi-ción de la rutina heredada (Assertion Redeclaration rule (1), [Mey97], pág. 573). En este sentido, se puede interpretar una redeclaración como una extensión o mejora de la funcionalidad de la rutina heredada: tiene menos requisitos para ser utilizada y asegura más cosas.
Para los dos primeros casos, la solución concreta no permite el uso de las cláusulas require y ensure en la redeclaración, sino que se deben usar require else y ensure then. La precondición resultante será la disyunción (el or) de la precondición heredada con la especicada en require else, y la postcondi-ción resultante será la conjunpostcondi-ción (el and) de la postcondipostcondi-ción heredada con la especicada en ensure then (Assertion Redeclaration rule (2), [Mey97], pág. 578).
En el último caso, el de la redeclaración de una función como atributo, lo que hay que resolver es el destino del contrato de la función original. Como los atributos son siempre accesibles, puede considerarse que la precondición resultante es True, que no es otra cosa que una debilitación de la precondición original. La postcondición original, por otra parte, se hereda como parte del invariante, ya que el atributo no puede tener postcondición pero debe garantizar las mismas propiedades que la función redenida.
10Una rutina diferida, deferred en el lenguaje de Meyer, es una rutina que no provee
imple-mentación. El concepto análogo en Java es el de los métodos abstractos.
11En Eiel esto se puede gracias al principio de Acceso Uniforme (Uniform Access). El
hecho de que una propiedad se encuentre implementada por memoria o por cálculo (es decir, como atributo o como función) permanece oculto en la clase. El valor de la propiedad x del objeto o siempre estará denotado por o.x ([Mey97], pág. 175).
Figura 3.2: Diagrama BON (Business Object Notation) para ilustrar el dynamic binding. C es un cliente de A y A' es una subclase de A. Fuente: [Mey97], pág. 571.
El principal argumento para todas estas reglas tiene que ver con el dynamic binding de las referencias a objetos. Cuando una clase C contiene una referencia a1 de tipo A, el objeto ligado a a1 puede ser tanto una instancia de A como de cualquier subclase de A, por ejemplo A' (Figura 3.2). Sin embargo, C se considera un cliente que contrata los servicios de A, y por lo tanto al invocar el método a1.r se asegurará de cumplir la precondición especicada para r en A y supondrá que r garantiza la postcondición especicada en esa misma clase. La rutina efectivamente ejecutada se determinará en tiempo de ejecución y puede ser una redeclaración hecha por cualquier subclase de A, pero siempre deberá cumplir el contrato que A ofrece a sus clientes.
3.2.4. Un cacho de teoría
La principal motivación teórica del Diseño por Contratos es la dención de clase como un Tipo Abstracto de Dato equipado con una implementación posi-blemente parcial ([Mey97], pág. 165). El TAD es la parte externamente visible de la clase, la interfaz utilizada por sus clientes.
Ahora, un Tipo Abstracto de Dato se compone de cuatro elementos ([Mey97], pág. 373):
un nombre para el tipo,
una lista de funciones (de las que sólo se especica el nombre y la signatura),
restricciones en la aplicabilidad de las funciones (es decir que las funciones pueden ser parciales)
y un conjunto de axiomas que expresan las propiedades de estas fun-ciones.
Los dos primeros elementos se pueden expresar, de una u otra manera, en cualquier lenguaje Orientado a Objetos con Tipado Estático. El contrato de una clase surge como el medio para que ésta pueda expresar las dos últimas características mencionadas.12
Las precondiciones son la materialización del concepto de función parcial en el lenguaje Eiel, ya que permiten denir el dominio de aplicabilidad de las funciones. El equivalente matemático a la precondición de una función f es la función característica del dominio de f.13
Por otra parte, las postcondiciones y los invariantes de clase son los mecanis-mos utilizados para expresar los axiomas del TAD. Un axioma aparecerá en una clase de una u otra manera dependiendo, principalmente, de las funciones que en él se mencionen. Resulta interesante ver con un poco más de detalle de qué manera inuye en la expresión de los axiomas la categorización de las funciones en funciones de creación, comandos y consultas.
La categoría de una función f : A1× . . . × An → X de un TAD de nombre T depende del lugar en que el tipo aparece mencionado en la signatura:
12Paradójicamente, la denición de clase como implementación de un TAD es un consenso
dentro del paradigma orientado a objetos, pero la mayoría de los lenguajes que lo implementan sólo permiten expresar la lista de las funciones.
13La función característica de un conjunto A ⊆ X es la función χ : X → BOOLEAN tal
Si X = T pero T no aparece en el dominio, f es una función de crea-ción. En la clase se expresa como un procedimiento de creación, y los axiomas que denen sus propiedades aparecen como postcondición del procedimiento.
Si X = T y además T aparece en el dominio, f es un comando y, por lo general, se expresa en la clase como un procedimiento (que modica el objeto y no devuelve ningún valor), en cuya postcondición aparecen los axiomas que denen su comportamiento.
Si X 6= T y T aparece en el dominio, f es una consulta. Se puede expresar en la clase como una función y, si n = 1, también como un atributo. Los axiomas que se reeren únicamente a consultas aparecen como postcondi-ciones de las funpostcondi-ciones correspondientes. Aquellos axiomas que mencionan sólo consultas de la forma f : T → X también pueden ser escritos como parte del invariante de clase.
Como puede verse, estos criterios no proveen una forma de traducir en aser-ciones cualquier conjunto de axiomas. El método de Meyer no propone denir los TADs en su forma matemática y luego llevarlos a la forma de clase, sino directamente denir los TADs en la forma del lenguaje Eiel. Las consideracio-nes teóricas hechas aquí permiten simplemente apreciar la conexión entre los mecanismos del lenguaje para denir TADs y la denición matemática de TAD. Además de la denición de TAD, otro aspecto teórico es la denición formal de implementación de un TAD, y éste también justica la necesidad de mecanis-mos de aserción. No desarrollaremecanis-mos aquí la teoría completa de implementación de TADs ([Mey97], pág. 375, y el viejo [Hoa72]), si no que rescataremos uno de sus elementos principales.
Sea C una clase implementada con atributos c1: T1, . . . , cn: Tn. El primer requisito para probar que C implementa un TAD A es denir una función de abstracción a : T1× . . . × Tn 9 A, que asigna a cada representación concreta un elemento del TAD. Si bien la función a debe ser suryectiva para que todo elemento de A tenga una representación en C, no necesariamente es inyectiva, dos elementos de C pueden representar uno mismo de A. Mucho menos será una función total, ya que pueden haber combinaciones de valores de los atributos
c1, . . . , cn que no sean representaciones válidas de elementos del TAD.
El dominio de la función de abstracción es, entonces, el conjunto de estados posibles en los que se puede encontrar C para representar un elemento de A, y se encuentra expresado en la clase como un invariante de implementación. Como las precondiciones, y desde un punto de vista matemático, el invariante de implementación es una función característica, en este caso del dominio de a.
3.3. Exportación Selectiva y Ocultamiento de
In-formación
La exportación selectiva (selective exports) es un mecanismo del lenguaje Eiel que permite indicar, para cada característica (feature) de una clase, qué otras clases pueden accederla (en el caso de un atributo) o invocarla (en el caso de un método). Representa una forma mucho más general de proveer distintos niveles de acceso que la dicotómica todo o nada ofrecida en la mayoría de los
lenguajes O-O. Permite que un conjunto de clases conceptualmente relacionadas puedan exponerse cosas entre sí, pero sin hacerlas públicas y sin la necesidad de introducir una noción de super-módulo que agrupe clases ([Mey97], pág. 209).14 Este mecanismo siempre se reere a la restricción del acceso en términos de la relación de uso y no de la de herencia. En el lenguaje Eiel las clases siempre podrán acceder a las características de las clases heredadas, es decir, a su implementación. Si bien es vox pópuli que la herencia de implementación es peligrosa y muchos lenguajes O-O proveen formas de retringirla, Meyer arma que no se han dado razones metodológicas para hacerlo, si no que son más bien de orden psicológico, y tienen que ver con la tradición de considerar la implementación como algo de bajo nivel ([Mey97], págs. 606-608).
Vale aclarar también que los atributos en Eiel sólo pueden ser exportados para ser consultados y nunca para ser asignados. Como el cliente que accede a una propiedad no sabe si se encuentra implementada como un atributo o como un método sin parámetros (de hecho la sintaxis es la misma), menos sabrá si tiene sentido asignarle un valor. Es por esto que la construcción sintáctica o.x := E es directamente inválida, y que toda posibilidad de modicar externamente el valor de un atributo deberá ser implementada a través de un procedimiento (un setter, por ejemplo).
En un extremo, una característica puede estar exportada (exported), en cuyo caso será accesible por cualquier cliente. Si no, estará exportada selectivamente (selectively exported), y en su declaración dirá la lista explícita de las clases que la pueden acceder. Si esta lista está vacía o sólo especica la clase NONE, se dirá que la característica es secreta (secret).15 Un feature exportado selectivamente a una clase también se considera exportado a todas sus clases descendientes (Selective Export Inheritance Rule, [Mey97], pág. 609).
Por otra parte, Meyer dene mecanismos para que una clase pueda redenir a su placer el estado de exportación (export status) de las características hereda-das, incluso restringiendo la visibilidad denida por la superclase. El argumento metodológico que utiliza para defender esta posibilidad es que no debería perder-se la posibilidad de utilizar la herencia, con todos sus benecios, por la existencia de excepciones de taxonomía ([Mey97], pág. 837).16Esta característica de Eiel entra en conicto con el dynamic binding, y Meyer lo resuelve de una manera que conserva el tipado estático.17
Todo intento de violación del estado de exportación de un método puede ser detectado estáticamente y por lo tanto se traduce en un error de compilación.
14No puedo evitar mencionar la analogía del televisor, en el que algunos controles están en
el frente para ser utilizados por el televidente común, mientras que otros se encuentran más ocultos y sólo son utilizados por los técnicos o por los conocedores de la casa.
15En realidad no es exacto decir que los clientes permitidos se listan en la declaración del
feature, pero esto es una cuestión sintáctica de Eiel y no es mi intención exponerla aquí (ver [Mey97], pág. 191).
16Uno de los tantos ejemplos de excepción de taxonomía que da Meyer es el del avestruz,
que, si bien es un ave, no puede volar. Comento este ejemplo más por lo simpático que por lo concluyente.
17Este es un problema más general y bastante complejo que no viene al caso profundizar.
Capítulo 4
Aplicando el método de
Meyer en Java
4.1. Diseño por Contratos con JML
Esta sección es una introducción a JML desde el punto de vista del Diseño por Contratos, y por lo tanto se recomienda antes haber leído la sección 3.2 o directamente el Capítulo 11 de [Mey97]. Las referencias principales serán el artículo Design by Contract with JML ([LC05]), el manual de referencia de JML ([LPC+07]), y el sitio web de JML ([JML]).
4.1.1. Introducción
Java Modeling Language es un lenguaje formal para la especicación del comportamiento de interfaces y clases en Java. Contiene como subconjunto a la notación utilizada por el Diseño por Contratos propuesto por Meyer, combi-nándola con el estilo de especicación basada en modelos de los lenguajes de la familia Larch y algunos elementos del cálculo de renamientos ([JML, LC05]). Aquí nos concentraremos en el uso de JML como herramienta para el Diseño por Contratos.
JML dene un lenguaje que permite dar la especicación de una clase en un archivo aparte o en el mismo texto de la clase a través de comentarios comenza-dos en /*@ o //@. Esto permite mantener la sintaxis de Java y al mismo tiempo utilizar herramientas especiales que tomen en cuenta las especicaciones.
El siguiente ejemplo muestra cómo expresar precondiciones, postcondiciones e invariantes, los tres tipos principales de aserción del Diseño por Contratos, con JML:
1 public class Person {
2 private /*@ spec_public @*/ String name;
3
4 //@ public invariant !"".equals(name);
5 6 //@ requires !"".equals(n); 7 //@ ensures name == n; 8 public Person(String n) { 9 name = n; 10 } 11
12 //@ ensures \result == name;
13 public /*@ pure @*/ String getName() {
14 return name;
15 }
16 }
Los objetos de tipo Person representan personas con un nombre asociado. El invariante de la línea 4 indica que este nombre no podrá ser vacío. Además, JML asume por omisión el invariante de que name no puede valer null. De la misma manera, asume la precondición implícita de que el parámetro n que toma el constructor será no nulo. La ejecución de la expresión new Person(null) daría una violación de esa precondición.
En general, y a diferencia de Eiel, en JML la opción por omisión es la no nulidad. Todos los atributos, parámetros y valores devueltos deberán ser distintos de null a no ser que se especique lo contrario con el modicador /*@ nullable @*/.1
En el ejemplo también puede verse que las aserciones tienen un nivel de acceso asociado. En el caso de los invariantes, éste debe especicarse de la misma forma que en el resto de los miembros de la clase. En el caso de las pre y postcondiciones, será el mismo nivel de acceso que el método que especican.2 Las aserciones públicas podrán referirse sólo a cosas públicas. La única forma de poder mencionar un nombre no público es declarándolo como público para la especicación con /*@ spec_public @*/, como en la línea 2 del ejemplo.3
El modicador pure para el método getName() indica que esta función no tiene ningún efecto colateral, es decir, que no cambia el estado del objeto. Este y sólo este tipo de funciones podrán ser utilizadas en las aserciones.
El lenguaje JML provee muchas expresiones y tipos de aserciones que no se encuentran en el Diseño por Contratos de Eiel, entre las cuales se pueden resaltar:
Variables y métodos del modelo (model) y variables fantasma (ghost), sólo para ser usados en la especicación.
Restricciones de historia (history constraints), que son aserciones que re-lacionan los estados sucesivos de un objeto.
Expresiones cuanticadas con \forall, \exists, \sum, \product, \min, \max, \num_of, que pueden ser o no ejecutables dependiendo del rango.
4.1.2. Algunos elementos de JML
En esta sección se describen algunos de los elementos principales de JML. Para una referencia completa, consultar [LPC+07]. Un elemento importante que no será tratado en este trabajo es la dención de datagroups.
1Esto facilita mucho el trabajo de especicación ya que en la práctica la gran mayoría de
las declaraciones se espera que no valgan null (2.8 Null is Not the Default, [LPC+07]). 2Existe otra forma de especicar métodos que se llama heavyweight, que no será tratada
en este trabajo. En la forma heavyweight, el nivel de acceso de las pre y postcondiciones se puede dar explícitamente.
Precondiciones y postcondiciones
Como sabemos, la semántica del Diseño por Contratos no es tan sencilla gra-cias a la herencia y a la posibilidad de redenir métodos. En JML se mantienen las mismas reglas básicas enunciadas por Meyer: una redenición sólo puede debilitar su precondición y fortalecer su postcondición.
La sintaxis utilizada en JML para especicar la redenición de un método es la siguiente:
//@ also //@ requires P; //@ ensures Q;
Suponiendo que las pre y postcondición del método original son P' y Q', la precondición resultante será P' || P y la postcondición será (P' ==> Q') && (P ==> Q) (a diferencia de la postcondición Q' && Q de Meyer). De hecho, la cláusula also se puede usar también, y con esta misma semántica, para extender la especicación de un método con uno o varios pares más de requires y ensures: //@ requires P'; //@ ensures Q'; //@ also //@ requires P1; //@ ensures Q1; . . . //@ also //@ requires Pn; //@ ensures Qn;
Variables y métodos del modelo y variables fantasma
JML permite denir variables que serán sólo para especicación, y por lo tanto estarán declaradas dentro del entorno de especicación y no podrán ser utilizadas en el código Java.
Las variables del modelo se denen con el modicador model, y se utili-zan para denir abstracciones del estado del objeto. Cada variable del modelo representa el valor de una expresión en términos de características concretas de la clase, y esta expresión se dene a través de la cláusula represents.
En la clase Persona del ejemplo anterior, puede denirse una variable del modelo _name de la siguiente manera:
//@ public model String _name;
//@ public represents _name <- getName();
Las variables fantasma se declaran con el modicador ghost, y su valor no está ligado a una expresión sino que puede ser inicializado y modicado, siempre que se lo haga dentro del entorno de JML.
Una posibilidad importante que permite JML es la de denir variables model y ghost en las interfaces. Para hacerlo, deberá utilizarse el modicador instance, o de lo contrario las variables se interpretarán como estáticas. Podemos apro-vechar esta posibilidad para denir, por ejemplo, un iterador de la siguiente manera:
1 public interface Iterator {
2 /*@ public model instance boolean _hasNext;
3 @ public represents _hasNext <- hasNext();
4 @
5 @ public ghost instance int _index = 0;
6 */
7
8 public /*@ pure @*/ boolean hasNext();
9
10 //@ requires _hasNext;
11 //@ ensures _index == \old(_index) + 1;
12 public Object next();
13 }
Aquí se declara una variable del modelo _hasNext, que sólo será una abre-viación de hasNext(), y una variable fantasma _index, que tendrá un valor propio. Como indica la línea 11, toda implementación de next() deberá incre-mentar el valor de _index. El siguiente es un ejemplo de implementación de un iterador bastante inútil:
1 public class DummyIterator implements Iterator {
2
3 public DummyIterator() {
4 }
5
6 public /*@ pure @*/ boolean hasNext() {
7 return true;
8 }
9
10 //@ also ensures \result.equals(new Integer(0)) && \fresh(\result);
11 public Object next() {
12 //@ set _index = _index + 1;
13 return new Integer(0);
14 }
15 }
En la línea 12 puede verse la sintaxis utilizada para modicar el valor de una variable fantasma. También aquí hay un ejemplo de fortalecimiento de postcon-dición, en la línea 10.4
Los métodos del modelo tienen todas las características de los métodos comunes pero sólo pueden ser invocados dentro de la especicación. Siempre con el modicador model, se pueden declarar tanto en el código Java como en el entorno de JML, pero sólo tiene sentido esto último ya que nunca podrá ser invocado fuera de la especicación. Pueden utilizarse, por ejemplo, para denir abstracciones parametrizadas, cosa que con una variable del modelo no se puede hacer.
Restricciones de historia
Las restricciones de historia permiten especicar la forma en que el estado de un objeto puede cambiar a lo largo del tiempo. Pueden expresar propiedades del estado en términos del estado anterior utilizando la notación \old(...), al igual que en las precondiciones, y por lo general se usarán para describir relaciones reexivas y transitivas.
En la clase Persona del último ejemplo, podría haberse escrito la restricción //@ public constraint name == \old(name);
4Aparece otro elemento nuevo, \fresh(e ), que se utiliza para indicar que el objeto
para expresar que el nombre de las personas no cambia a lo largo de su vida. De haber denido el atributo age (edad) seguramente habríamos especicado lo siguiente:
//@ public constraint age >= \old(age);
Las restricciones de historia, como los invariantes, se consideran parte implí-cita de las postcondiciones de todos los métodos. También como los invariantes, las clases heredan todos los constraints especicados en sus superclases y supe-rinterfaces.
Comportamiento excepcional
JML permite especicar tanto las excepciones que puede tirar un método como la postcondición en caso de que esto suceda. Se puede expresar que un método sólo tira como excepciones instancias de E1, ..., En, y que la postcondi-ción cuando se tira Ei es Pi de la siguiente manera:
//@ signals_only E1, ..., En; //@ signals (E1 e) P1; .
. .
//@ signals (En e) Pn;
Por omisión, JML asume que un método puede tirar todas las excepciones declaradas en la cláusula throws de Java. Se podrá decir que un método no tira ninguna excepción de la siguiente manera:
//@ signals_only \nothing;
4.1.3. Las JML Tools
Las JML Tools son un conjunto de herramientas de software libre desarro-lladas para trabajar con JML. Los principales componentes de las JML Tools son:
jml-launcher: Interfaz gráca para usar las JML Tools. jml: Vericador de sintaxis JML.
jmlc: Compilador JML, que es un compilador de Java extendido con che-queo de aserciones en tiempo de ejecución.
jmldoc: Generador de documentación, que es un Javadoc extendido con las especicaciones JML.
jmlspec: Generador de esqueletos de especicación JML a partir del có-digo fuente Java.
jmlunit: Herramienta de unit testing, que genera código de testeo JUnit basado en las especicaciones JML.