Sobre pruebas y errores

5 comentarios
Veo en las noticias las imagenes de una prueba de carga en un nuevo puente de una autovía en Galicia (España). Durante un momento me quedo absorto mirando la larga flota de camiones sobre el majestuoso puente. Impresiona. No puedo evitar pensar: Vaya! eso sí que es una prueba manual. Y luego yo quejándome sobre las pruebas manuales que hacemos en el desarrollo de proyectos software...

Bastan un par de segundos para darme cuenta de la tontería de mi reflexión. Si eso fuera una primera ejecución de una prueba exigente sobre un proyecto software recien construido, el puente se habría caido arrastrando a la flota de camiones tras él.

En el caso del puente, lo que no estamos viendo es todo el proceso de pruebas y control de calidad, que se ha realizado previamente en cada una de las fases del proyecto para evitar errores.

Pero comparar nuestro mundo de desarrollo software -¿ingeniería software?- con el de la construcción o cualquier otra ingeniería es una equivocación. Una equivocación torpe, injusta y desafortunada, porque, entre otras cosas, hace imaginarse a un programador como a un obrero. Así nos va.

Aunque centrémonos en los errores. Errar es humano. Obvio. A veces estamos distraidos, cansados, estresados, desmotivados o simplemente no somos perfectos y se nos escapan cosas.

Otro hecho es que los proyectos software salen a producción con demasiados errores. También obvio si estudiamos el ineficaz proceso de pruebas que se sigue en la mayoría de proyectos, basado en unas pruebas mínimas, manuales y sin documentar. Por lo que las pruebas dificilmente se repiten en el tiempo, aunque se modifique código afectado, haciendo aparecer nuevos errores o, peor aun, haciendo reaparecer viejos errores. ¿Vosotros compraríais algo cuyo proceso de pruebas fuera así?

Lo primero no tiene solución. Pero sí se puede minimizar el efecto. Contratando talento y con motivación.
Lo segundo sí tiene solución. Aplicar un proceso profesional de pruebas, basado en pruebas automatizadas, completas, independiente y repetibles. Los errores seguirán produciéndose, pero la mayoría serán detectados antes de llegar a producción.

Por supuesto, siempre hará falta alguna prueba manual pero, al igual que en el puente, será más un mero trámite de aceptación que el actual infierno de prueba y error sin fin.

Nuevo cambio de look y AdSense

0 comentarios
Aprovecho para anunciar un par de cambios en el blog: (1) nuevo cambio de look y (2) AdSense.

Hacía tiempo que me había cansado del anterior template, un día sin querer dí con este The Journalist y hoy he decidido probarlo, tras unas mínimas modificaciones. No tiene más.

El tema de AdSense sí requiere un poco más de explicación. No pretendo monetizar el blog. No creo ni que le fuera a sacar un euro aunque lo intentara. Sin embargo, sí quiero probar AdSense y ver cómo funciona de primera mano. Últimamente se me ha reactivado la vena emprendedora, así que quiero ver cómo va esto de la publicidad.

Como siempre, cualquier opinión sobre alguno de los 2 temas será más que bievenido!

Buenas practicas para desarrollar servicios web SOAP

12 comentarios
Como complemento a mi último post, Arquetipo de WSDL interoperable, he decidido publicar este post con varias buenas prácticas para desarrollar servicios web SOAP. Como siempre, son sólo buenas prácticas según mi criterio, conocimiento y experiencia.

  • Analiza qué servicios web y con qué operaciones hay que desarrollar. Parece de perogrullo, pero es uno de los fallos más repetidos. Según mi experiencia suelen darse 2 esquemas a la hora de desarrollar servicios web: (i) el servicio web dios con todas las operaciones para él y (ii) un servicio web por operación. Ambos son malos. El primero incluso peor. Así que piensa y diseña servicios web con las responsabilidades bien repartidas, que sean cohesivos, extensibles, escalables y reutilizables.
  • Escribe tu mismo el fichero WSDL (Contract-First). Es el interfaz, el contrato y, en definitiva, la clave para una interoperabilidad real e independiente de la tecnología. Además los generadores de WSDL pueden introducir dependencias con una tecnología concreta. Por eso merece la pena aprender a escribir WSDL (aquí) y schemas XSD (aquí).
  • A la hora de diseñar el interfaz de las operaciones, ten siempre en cuenta que es mucho más eficiente un único mensaje enorme que el equivalente en multiples mensajes.
  • Sé coherente con la nomenclatura de namespaces de la organización. No hay nada que de peor impresión que un servicio web que no ha cuidado los namespaces.
  • El WSDL debe ser compatible con el WS-I Basic Profile. El WS-I Basic Profile es un conjunto de especificaciones y buenas practicas definidas por la industria para obtener servicios web interoperables. Actualmente la última versión final publicada es la 1.1. Como mínimo, evita siempre los estilos RPC y sus tipos de datos no XML (SoapArrays), en su lugar usa el estilo Document/literal.
  • Usa http://localhost:puerto como dirección url del endpoint y deja que sea el motor de webservices el encargado de sustituirla por la real. Así evitarás tener un fichero WSDL por entorno.
  • Separa la definición de los mensajes del fichero WSDL. Para ello, diseña por separado un schema XSD donde se definan los mensajes y que sea importado por el fichero WSDL. Las principales ventajas son (1) reduce el tamaño/complejidad del WSDL, (2) permite utilizar editores especializados para el diseño del schema XSD y (3) permite reutilizar schemas y namespaces.
  • Define los mensajes de forma detallada mediante las restricciones de los schemas XSD. De esta forma podrás validar los mensajes a nivel de XML mediante el api XML u OXM que uses, sin necesidad de implementar código propio.
  • A la hora de diseñar el schema XSD, crea tipos y elementos globales (a nivel raíz) para poder reutilizarlos, tanto a nivel de elementos XML como clases del lenguaje de implementación del servicio web.
  • Además, usa minOccurs=0 para definir un elemento como opcional y nillable=true para indicar que un elemento puede ser vacío pero siempre estará presente en el mensaje XML. Ojo, no es lo mismo.
  • Si necesitas enviar ficheros adjuntos (attachments), hazlo a nivel de http attachment y no como un elemento del mensaje XML.
  • Automatiza el proceso de generar el Skeleton y las clases OXM de mensajes del servicio web a partir del WSDL (wsdl2code).
  • Para realizar pruebas unitarias del servicio web no necesitas desplegarlo, puedes programar tus tests a nivel de la clase Skeleton. Ahorraras mucho tiempo y ya desplegarás para las pruebas de integración o alguna demo.
  • Guarda log de los mensajes de entrada y salida junto con datos del cliente (ip, usuario), a nivel de fichero o base de datos.
  • Redacta un documento Guía de pruebas de integración que sea completo e incluya casos de error y no sólo los casos básicos.

Arquetipo de WSDL interoperable compatible con WS-I Basic Profile 1.1

3 comentarios
En este post voy a publicar un WSDL de ejemplo que cumple con el WS-I Basic Profile 1.1.

La clave de la interoperabilidad entre servicios web SOAP está en su interfaz WSDL. El WS-I Basic Profile es un conjunto de especificaciones y buenas prácticas definidos por la industria para desarrollar servicios web interoperables independientemente de la tecnología con que fueron desarrollados. Su última versión final es la 1.1 y debería ser un must-know para todos aquellos que tengan que definir un WSDL.

El WSDL de ejemplo está diseñado para que use un schema XSD donde definir los mensajes de petición y respuesta de las operaciones. De esta forma se puede usar un editor de XSD como ayuda para diseñar la estructura de los mensajes, que es la parte más importante del WSDL y que requiere el verdadero esfuerzo intelectual. Dejando de esta forma el proceso de definir el fichero WSDL a un mero trámite de copy&paste.Además es una buena práctica en una SOA publicar los schemas xsd para reutilizar sus elementos.

Este WSDL sólo tiene 1 operación. Además usa los siguientes literales como ejemplo:
  • Nombre del servicio: nombreServicio
  • Nombre de la operación: nombreOperacion
  • TargetNamespace del servicio: http://dominio/ws/nombreServicio
  • TargetNamespace del schema xsd: http://dominio/ws/nombreServicio/schema/msg

El fichero schema xsd nombreServicio_msg.xsd sería el siguiente:

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns:tns="http://dominio/ws/nombreServicio/schema/msg"
xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://dominio/ws/nombreServicio/schema/msg">
<element name="nombreOperacionRequest">
<complexType>
<sequence>
<element name="campo1" type="string"/>
<element name="campo2" type="string"/>
</sequence>
</complexType>
</element>
<element name="nombreOperacionResponse">
<complexType>
<sequence>
<element name="campo1" type="string"/>
<element name="campo2" type="string"/>
</sequence>
</complexType>
</element>
</schema>
La operación del servicio tiene 2 elementos de entrada y 2 de salida, todos de tipo string, a modo de ejemplo. Puedes modificar los mensajes existentes o crear mensajes para nuevas operaciones a tu gusto. No olvides modificar el targetNamespace.
Si el schema xsd se complica puedes plantearte dividirlo por operaciones o por entrada y salida.
Este fichero puede ser descargado aquí.

El fichero wsdl nombreServicio.wsdl sería el siguiente:

<?xml version="1.0" encoding="UTF-8"?>
<definitions name="nombreServicio"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl"
xmlns:tns="http://dominio/ws/nombreServicio"
xmlns:msg="http://dominio/ws/nombreServicio/schema/msg"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:ns="http://schemas.xmlsoap.org/soap/encoding/"
targetNamespace="http://dominio/ws/nombreServicio">
<!-- Importacion de schemas -->
<import namespace="http://dominio/ws/nombreServicio/schema/msg"
location="./nombreServicio_msg.xsd"/>
<!-- Definicion de mensajes -->
<message name="nombreOperacionRequest">
<part name="body" element="msg:nombreOperacionRequest"/>
</message>
<message name="nombreOperacionResponse">
<part name="body" element="msg:nombreOperacionResponse"/>
</message>
<portType name="nombreServicio">
<!-- Relacion Mensaje-Operacion -->
<operation name="nombreOperacion">
<input message="tns:nombreOperacionRequest"
wsaw:Action="urn:nombreOperacion"/>
<output message="tns:nombreOperacionResponse"
wsaw:Action="urn:nombreOperacion"/>
</operation>
</portType>
<binding name="nombreServicioBinding" type="tns:nombreServicio">
<soap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http"/>
<!-- Definicion de operaciones -->
<operation name="nombreOperacion">
<soap:operation soapAction="urn:nombreOperacion"/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
</binding>
<service name="nombreServicio">
<port name="nombreServicioPort" binding="tns:nombreServicioBinding">
<soap:address location="http://localhost:8080"/>
</port>
</service>
</definitions>

Lo primero sería modificar los nombres del servicio, operación y targetNamespaces de ejemplo. Puedes añadir nuevas operaciones a tu gusto. Como puedes ver, he puesto comentarios indicando los sitios que deberían ser modificados.
No cambies la url del endpoint. Por lo general, los servidores de webservices detectarán la url y realizarán la modificación de forma automática. De este modo te evitas tener una copia del WSDL por entorno (desarrollo, pruebas, producción, etc.).
Este fichero puede ser descargado aquí.

Una vez realizadas las modificaciones convenientes no olvides validarlo todo, el schema xsd y el wsdl.