Quan evitar l’acoblament

Posted: Febrero 5th, 2009 | Author: Jose Raya | Filed under: agilogy | Comentarios desactivados

“Acoblament baix” és un dels principis de disseny de software més àmpliament acceptats (de fet, no crec que poguem trobar cap referència enlloc on algú indiqui que és bó mantenir l’acoblament alt) però si apliquem aquest principi sense cap altre criteri, ens podem trobar [LAR] amb un disseny molt pobre on alguns objectes només actuin com a contenidors de dades (i no tinguin cap acoblament amb altres classes) mentre que altres concentrin tots els acoblaments i totes les responsabilitats del sistema. Per tant, i citant en Larman Some moderate degree of coupling between classes is normal and necessary for creating an object-oriented system in which tasks are fulfilled by a collaboration between connected objects.

Un cop acceptem que és necessari assumir un cert grau d’acoblament al sistema, necessitem establir criteris per a decidir, entre dos acoblaments, quin és més greu per tal de mantenir un bon disseny. El propi Larman ens ofereix algunes pistes a la discussió del patró GRASP: Hem d’evitar l’acoblament cap als elements menys estables o amb més possibilitats d’evolucionar.

Però en Larman no és l’únic autor que ha tractat aquest tema. D’altres, com ara en Robert C. Martin, l’han tractat des del punt de vista de la gestió de dependències. El principi d’inversió de dependències diu que:

  • a. Els elements d’alt nivell (d’abstracció) no haurien de dependre dels de baix nivell. Tots dos haurien de dependre d’abstraccions
  • b. Les abstraccions no haurien de dependre dels detalls. Els detalls haurien de dependre de les abstraccions

D’aquest principi podriem extreure un altre criteri: Evitar els acoblaments cap a elements de més baix nivell d’abstracció.

Finalment, una tercera variable que hem de tenir en compte és que el concepte d’acoblament depèn de quina sigui la unitat organitzativa que volguem tractar. Per exemple, podem considerar els acoblaments entre classes, entre paquets, mòduls o subsistemes. En Robert C. Martin [MAR] dedica un capítol sencer a la gestió de l’acoblament entre paquets, mentre que altres autors com en Bertrand Meyer [MEY] o en Martin Fowler també tracten el tema de l’acoblament associat al concepte de mòdul o subsistema. Per tant, és molt important gestionar l’acoblament a nivell de paquets.

Recapitulant, doncs, ens trobem amb tres variables o criteris per decidir: La possibilitat de canvis, el nivell d’abstracció i la pertanyença a un mateix paquet. En realitat, però, si hem fet una bona organització de paquets, totes les classes d’un mateix paquet tindran un mateix nivell d’abstracció i, a més, hauran previst el mateix tipus de canvi, de manera que, si hem fet una bona organització de paquets, el criteri principal és evitar els acoblaments cap a classes d’altres paquets, especialment si el seu nivell d’abstracció és més baix que el del paquet de la classe en qüestió ja que son les que ténen més possiblitats de treballar a un nivell d’abstracció diferent o de canviar per motius que poden no haver estat previstos al disseny de la nostra classe.

Significa això que la resta d’acoblaments no s’han d’evitar? Mai. Això només significa que, en termes generals, hem d’evitar, de manera preferent, els acoblaments cap a classes que pertanyin a altres paquets. Per exemple, és una mala decissió afegir un acoblament cap a una classe d’un altre paquet per evitar un acoblament cap a una classe del mateix paquet.

Referències:

[LAR] Craig Larman, Applying Uml and Patterns, 3rd Edition
[MAR] Robert C. Martin, Agile Software Development: Principles, Patterns and Practices
[MEY] Bertrand Meyer, Object Oriented Software Construction


Domain Model: Del disseny a la implementació persistent

Posted: Febrero 5th, 2009 | Author: Jose Raya | Filed under: agilogy | Comentarios desactivados

A l’article Domain Model: De l’anàlisi al disseny hem parlat del patró de disseny Domain Model i de com arribar a un conjunt de classes software a partir d’un model conceptual d’anàlisi. El que ens proposem en aquest article és donar el següent pas cap a la implementació i tractar la problemàtica de com fer persistents les dades que conté aquest model. La solució proposada es basarà en la tecnologia JPA (Java Persistence API) que ens permet lligar aquest model del domini amb l’estructura de la base de dades relacional.
JPA defineix una família d’implementacions del patró Data Mapper que defineix en Martin Fowler, al seu llibre Patterns of Enterprise Application Architecture. Aquesta tecnologia assumeix que hi ha una base de dades relacional que té una certa similitud amb el model del domini ja que totes dues haurien de ser derivats d’un mateix model: El model conceptual del domini.
El nostre subsistema JPA (a l’article farem servir Hibernate com a referència) requereix que se li subministrin dades addicionals sobre com s’ha d’establir la correspondència entre el model del domini i el model físic de la base de dades. El principi d’inversió de dependències ens diu que hem d’implementar aquest model del domini sense dependre de detalls específics de la plataforma, per la qual cosa hauriem de subministrar aquestes metadades de manera independent del codi de les classes del model del domini (de fet, aquest és l’enfocament inicial de moltes eines de mapeig objecte-relacional i encara es pot fer servir amb JPA). A la pràctica, però, s’ha demostrat que el fet d’haver de mantenir dos fitxers diferents per a cada entitat, un fitxer java amb la classe que la implementa i un fitxer (típicament xml) de mapeig amb les dades de persistència i mantenir-los sincronitzats és també costós i propens a errors, per la qual cosa necessitem un enfocament mixte. Una de les grans novetats de JPA ha sigut, precissament, aportar aquest enfocament mixte gràcies a l’ús d’anotacions (novetat de Java 5). Aquesta solució, com qualsevol solució basada en anotacions, implica un cert acoblament del codi java cap les anotacions de JPA (és necessari JPA per compilar el codi) però permet l’execució del codi anotat en un entorn no-JPA.
Finalment, necessitem un punt d’entrada al subsistema JPA que permeti a les classes de la capa de domini recuperar instàncies d’objectes de la base de dades o actualitzar la base de dades amb les dades que tenim al model del domini. JPA ens ofereix la interfície EntityManager que ens dóna accés a aquest subsistema amb una interfície prou simplificada per executar consultes, recuperar instàncies a partir del seu identificador o actualitzar instàncies. Una opció que ens podem plantejar, doncs, és fer servir l’EntityManager des de les classes de la capa de domini; el principal problema d’aquesta opció és que, si apliquem el principi d’inversió de dependències , les classes de la capa de domini no haurien de dependre de l’EntityManager ja que aquest és menys abstracte i, per tant, hem d’introduir una abstracció intermitja: El controlador de dades o diccionari de dades. Aquesta interfície definirà les operacions que la capa de domini necessita de la capa de dades i la seva implementació farà d’adaptador entre aquesta interfície i la interfície oferta per l’EntityManager. A continuació es mostra un diagrama UML amb els elements que formarien part d’aquesta solució:
Adaptador de dades

Conclusions

S’ha proposat una solució que permet sincronitzar el model del domini amb el model persistent de les dades amb un cost de codificació mínim ja que només s’han de codificar les metadades de mapeig, les consultes que es considerin necessàries i els adaptadors de dades. A més, la solució proposada permet mantenir un compromís òptim entre independència entre el model del domini i el subsistema de persistència i facilitat de manteniment mitjançant l’ús d’anotacions.
No s’ha considerat a l’article com definir aquestes metadades de mapeig (es poden trobar a l’article Implementació de models conceptuals persistents amb Java i JPA ).


Identificació de casos d’ús

Posted: Febrero 5th, 2009 | Author: Jose Raya | Filed under: agilogy | Comentarios desactivados

La major part del material d’aquest article està basada en les idees del llibre Writing Effective Use Cases d’ Alistair Cockburn. La meva intenció amb aquest document és donar una visió general de les idees que allà es detallen amb exemples i explicacions més exhaustives.

¿Què és un cas d’ús?

Un cas d’ús captura un contracte entre algú que fa servir un sistema i el propi sistema. Descriu el comportament del sistema indicant com ha de reaccionar a les accions de l’usuari. Per tant, els casos d’ús del sistema formen part del recull de requisits del mateix però no són tots els requisits (no inclouen la interfície gràfica d’usuari, regles de negoci, formats de dades, requisits tecnològics, requisits legals, etc.).

Un cas d’ús contempla diversos escenaris possibles. Alguns acaben bé i d’altres no, però tots els escenaris formen part del cas d’ús. Hi ha un escenari principal: aquell en el qual l’entitat qui ha engegat el cas d’ús aconsegueix satisfer l’objectiu pel qual l’havia engegat (hauria de ser el més “habitual”). Ex: En el cas d’ús “Comprar accions via web”, l’escenari principal és aquell en què el comprador aconsegueix comprar les accions.

¿A qui li afecta el cas d’ús?

Un cas d’ús descriu un contracte entre un “stakeholder” i el sistema. Un stakeholder és qualsevol entitat amb algun interés sobre el sistema, independentment de si interactua amb ell o no. Ex: El director general d’una empresa pot estar interessat en el sistema de facturació encara que no hi interactui directament.
Un actor, en canvi, és una entitat (una persona o un sistema informàtic) que interactua amb el nostre sistema. L’actor principal d’un cas d’ús és l’entitat que inicia la interacció amb el sistema.

¿Com es poden identificar ?

L’actor principal, quan decideix interactuar amb el sistema, ho fa amb un objectiu: aprofitarem aquest fet per descriure els casos d’ús en termes d’actors i objectius i per descobrir els casos d’ús:

  • Primer identifiquem els actors principals
  • Després identifiquem els casos d’ús per cada actor

Com que no només els actors tenen interessos respecte al sistema, podem generalitzar aquest enfocament a tots els stakeholders. Un cop identificat el cas d’ús, hem de tenir en compte que quan un actor engega un cas d’ús amb un objectiu el sistema té la responsabilitat de satisfer aquest objectiu. Per a dur a terme aquesta responsabilitat haurà d’identificar subobjectius, recolzar-se en altres actors de suport, establir mecanismes per a recuperar-se en cas de no poder satisfer aquest objectiu, etc.
Aquesta descomposició ens porta a plantejar-nos la següent qüestió:

Fins a quin punt descomposem els casos d’ús?

Normalment en tindrem prou amb tres nivells de detall (tot i que, al seu llibre, en Cockburn identifica alguns més).

  • Objectius generals (summary) (”sky-level”)
  • Objectius d’usuari (user) (”sea-level”)
  • Subobjectius (subfunctions) (”fish-level”)

Objectius generals

Son el nivell més alt i ténen com a propòsit i mostren el context en el què operen els objectius d’usuari. Mostren la seqüència relativa i el cicle de vida dels objectius relacionats. A més, serveixen com a “resum” del contingut dels casos d’ús que té per sota.

Objectius d’usuari

Son els més importants ja que són aquells per causa dels quals els usuaris (de manera més general, els actors principals) interactuen amb el nostre sistema. Idealment, un cas d’ús d’aquest nivell ha de proporcionar un cert valor per a l’actor que l’inicia; com a heurístic per identificar aquest valor podem fer qualsevol d’aquestes dues proves:

  • Test del café: Quan hagi acabat el cas d’ús, me’n puc anar a fer un café?
  • Test del sou: Si faig això 10 vegades en un dia, està justificat dir que m’he guanyat el sou?

Subobjectius

Son aquelles tasques que es requereixen per a dur a terme els objectius dels usuaris com ara cercar un producte, guardar un fitxer, etc. Normalment, només s’han de descriure en aquells casos en què la interacció sigui rellevant per algún motiu i que no hagi quedat clara en el cas d’ús d’usuari què l’inclou.

Errors habituals

Finalment, un petit recull d’errors habituals en el procés d’identificació i descripció dels casos d’ús:

  • Massa dependència respecte a la interfície d’usuari
  • Els casos d’ús formen part del recull de requisits, no del manual d’usuari. Per tant, el cas d’ús hauria de parlar d’intencions i objectius, no de pantalles.

  • No parlar sobre el sistema
  • Si només indiquem què fa l’actor però no indiquem què fa el sistema, no estem describint el comportament del sistema. Per tant, sempre hem d’intentar posar qui fa què

  • Objectius de molt baix nivell
  • La descomposició de casos d’ús generals en casos d’ús detallats és semblant a la descomposició funcional, però els casos d’ús són requisits, no disseny i, per tant, l’estructura dels casos d’ús no s’hauria de reflectir al codi. La descomposició funcional no funciona bé per als sistemes OO ja que dificulta la reusabilitat dels objectes