Desarrollar software esencial con Python: una historia de éxito

Con la colaboración de expertos clientes y partners del sector, Integrated Informatics Inc. ha desarrollado el kit de herramientas geodésicas, un producto comercial. Con este kit de herramientas, los usuarios pueden cargar, analizar, representar cartográficamente, auditar y generar informes para mediciones sísmicas y de pozos. Las herramientas de la caja de herramientas toman datos binarios y de texto formateados de acuerdo a estándares personalizados y del sector (como UKOOA, SEG-Y y SEGP1, entre otros) y los cargan en un esquema de clases y tablas de entidad.

En las secciones siguientes, Integrated Informatics Inc. analiza las razones para elegir a Python como el lenguaje para desarrollar y ofrecer su producto comercial. Asimismo, se describen los beneficios que ha aportado el uso de Python a su entorno de desarrollo de software y se ofrecen ejemplos que demuestran que Python es algo más que un lenguaje de secuencia de comandos. Por último, se examina la utilización de bibliotecas de código abierto en su producto.

Nadar en un mar de mediciones

Los datos de mediciones sísmicas y de pozos son un elemento fundamental de la base de datos de cualquier empresa de la industria del petróleo y el gas, y se emplean para diferentes usos, como visualización, descubrimiento de recursos e inventario. La industria del petróleo y el gas tiene una larga y amplia trayectoria de utilización de equipos informáticos y almacenamiento digital de datos. A lo largo de todo este tiempo, han surgido numerosos y variados estándares de almacenamiento topográfico, y las empresas en cada momento se han decantado por el estándar que mejor se adecuaba a sus necesidades o incluso han desarrollado estándares propios. El resultado ha sido la proliferación de archivos topográficos aparentemente similares, pero que con frecuencia presentan sutiles diferencias.

Puesto que la información topográfica ha existido durante mucho tiempo, no sorprende que haya disponibles tantas herramientas para el procesamiento de los datos. El problema es que tales herramientas no suelen formar parte de una solución de software mayor. Se han creado para visualizar y realizar ciertas tareas de procesamiento, pero con frecuencia no funcionan bien con el resto de la base de datos empresarial. Esta situación no es la ideal, ya que sólo es posible aprovechar todo el potencial de estos datos cuando se superponen, integran y analizan conjuntamente. Como la mayor parte de las empresas de la industria del petróleo y el gas emplean la pila de Esri como su software SIG principal, resulta necesario introducir capacidades para cargar datos sísmicos y de pozos de diversos formatos directamente en ArcGIS.

Desarrollo en un entorno corporativo - ¿Por qué Python?

Para el desarrollo de las herramientas geodésicas, teníamos la opción de usar un enfoque basado en ArcObjects, sin embargo, elegimos Python principalmente por dos motivos: 1) Velocidad de desarrollo y 2) Facilidad de implementación.

Velocidad de desarrollo

Python y el marco de geoprocesamiento están estrechamente integrados, y Python es el lenguaje recomendado para implementar herramientas de secuencias de comandos. Elegir Python supone que uno, como desarrollador, puede dedicar el tiempo a codificar las funcionalidades y no la interfaz de usuario. A su vez, esto significa que es posible ofrecer los productos a los clientes más rápidamente de lo que se podría esperar en otras circunstancias, porque las partes principales del proyecto (la interfaz de usuario) ya han sido tratadas. Por ejemplo, cuando se crea una herramienta a través del marco de geoprocesamiento, se obtiene una herramienta que se asemeja y actúa como las herramientas principales que ofrece ArcGIS. Esto significa validación, controles de interfaz de usuario y estilo de documentación predeterminados que permiten que las herramientas predeterminadas se mezclen sin complicaciones con otras partes de la aplicación, como Model Builder.

Merece la pena destacar que el tiempo de desarrollo para el programador también se reduce debido a la naturaleza misma de Python. Guido van Rossum, el autor de Python, creó el lenguaje para que resultara sencillo e intuitivo, de código abierto, fácil de comprender y adecuado para las tareas cotidianas. Para usted, el analista SIG convertido en desarrollador o mero aficionado, significa que Python es fácil de aprender y de leer. Dedicará menos tiempo a aprender y más a crear soluciones y mejorar el flujo de trabajo.

La caja de herramientas geodésicas actualmente contiene más de 40 herramientas. Nos ahorramos una enorme cantidad de tiempo, puesto que no tuvimos que programar interfaces de usuario para cada una de ellas. El tiempo ahorrado nos permitió invertir muchos esfuerzos en probar las herramientas, crear un sistema de pruebas, mejorar el rendimiento e introducir innovaciones y nuevas funciones.

Facilidad de implementación

Uno de los aspectos más atractivos de una solución Python es su fácil implementación. No es preciso registrar dll o ejecutar complicadas instalaciones, ni hay dependencias COM de las que preocuparse. Con la caja de herramientas geodésicas, podemos simplemente comprimir la solución en nuestra oficina y descomprimirla en una ubicación accesible en la red del cliente. Con el código disponible, el cliente sólo debe agregar la caja de herramientas a ArcGIS Desktop para disfrutar de acceso a la funcionalidad.

En muchas grandes corporaciones, la instalación del software es dominio del departamento de TI, y facilitar el software a los empleados de la empresa es su tarea y, con frecuencia, su principal problema. Como proveedor de soluciones, cuanto más sencilla se haga la instalación, más agradecido estará el personal de TI y antes podrán los clientes acceder a la nueva funcionalidad. Para Integrated Informatics, el uso de Python supone que garantizamos el proceso de instalación más sencillo posible y el tiempo de respuesta más breve para nuestros consumidores, lo que se traduce en clientes satisfechos.

Desarrollo en un entorno corporativo - Pruebas automatizadas

El código Python para la caja de herramientas geodésicas contiene más de 5000 líneas de código (sin incluir los paquetes de código abierto). Como sucede con el resto de productos comerciales, nuestros clientes nos envían con regularidad peticiones de mejoras, que intentamos satisfacer lo antes posible. Sus peticiones abarcan desde nuevos parámetros a conjuntos completos de herramientas. Por tanto, es importante para nosotros saber cuándo afectan los cambios a la funcionalidad existente y si los posibles cambios han causado el fallo de las herramientas. Al contar con más de 40 herramientas, cada una de ellas con hasta docenas de parámetros, probar cada herramienta de forma manual no es un sistema eficaz. Para lograr los tiempos de respuesta deseados de las peticiones con el nivel de calidad esperado, la realización de pruebas automatizadas es absolutamente indispensable.

Se dice que Python viene con "las baterías incluidas", por lo que para las pruebas sólo fue necesario examinar el propio Python para al menos parte de la solución. Python cuenta con un excelente módulo estándar llamado unittest, que forma parte de la instalación de Python central. Para cada herramienta, existe una secuencia de comandos de prueba independiente con la que se ponen a prueba muchas permutaciones diferentes de parámetros y entradas de datos. Con conjuntos de prueba individuales para cada herramienta, podemos ser muy precisos sobre lo que probamos y eficaces con el tiempo invertido en los días laborables.

Los conjuntos de prueba individuales para cada herramienta son un buen paso, pero resulta esencial que estas secuencias de comandos de prueba se ejecuten de forma automatizada con regularidad, no sólo cuando se recuerde hacerlo. Últimamente está en boga la noción de "integración continua", la idea de que, después de cada cambio introducido en la base del código, un mecanismo de activación inicia todas las pruebas del conjunto. Esta opción puede resultar excelente para ciertos tipos de base de código y pruebas, sin embargo, no siempre es práctica para las herramientas que realizan las tareas de procesamiento más pesadas, como las pruebas de alta frecuencia. Más importante es la idea de que la prueba se active de forma regular. Puede ser cada noche, semanal o incluso mensualmente, dependiendo de la frecuencia con la que se actualice la base de código. Con la ejecución automatizada del conjunto de pruebas, siempre se estará al tanto de lo que sucede con el código para, en caso de producirse un error en la base de código, saber con rapidez que existe un problema y corregirlo.

Reutilización de código: las clases en Python

Uno de los principios básicos de la programación es evitar la duplicación de código. Hay un par de formas de evitar dicha duplicación y hacer que la base de código sea más efectiva. En primer lugar, se pueden usar funciones para contener fragmentos de código que se reutilizan una y otra vez. Las funciones pueden hacer mucho y son el primer paso en el camino para reducir la duplicación de código. En las bases de código de mayor tamaño, las funciones están limitadas en lo que pueden hacer (aunque tienen su lugar) y, en muchos casos, resulta apropiado empezar a crear clases.

Aunque se considera que Python se ha ideado como lenguaje de secuencias de comandos en el contexto del software de Esri (por ejemplo, observe el uso del término "scripting" (secuencias de comandos) en '"arcgisscripting"), en realidad es un lenguaje de programación completamente orientado a objetos (OO). Como tal, los programadores tienen la capacidad de crear clases y jerarquías de clases completas mediante la herencia. En bases de código grandes, un código de estilo OO bien escrito puede ayudar a abstraer conceptualmente ideas complejas, reducir la duplicación de código y aislar el código en pequeñas porciones concisas que hacen que sea más fácil modificarlo, administrarlo y probarlo.

El sencillo ejemplo que se ofrece a continuación pretende servir de discreta introducción a las clases de Python y una pequeña jerarquía de clases.

from os.path import basename

class AbstractReport(object):
    """
    Base parsing class
    """
    _table_fields = None

    def __init__(self, file_path, records):
        """
        initializes the class
        """
        self._file_path = file_path
        self._records = records

    def calc_coords(self):
        """
        calculates coordinates to be written to report table
        """
        raise NotImplementedError

    def write_table(self):
        """
        parses the records in the file
        """

        coords = self.calc_coords()
        print ('writes a table using fields %s '
               '\nand calculated coords %s to file %s' %
               (self._table_fields, coords, basename(self._file_path)))


class OrthoCheckReport(AbstractReport):
    """
    Orthongonal Check Report Class
    """
    _table_fields = ['FLD_A', 'FLD_B', 'FLD_C']

    def calc_coords(self):
        """
        calculates coordinates to be written to report table
        """
        print ('special Orthogonal Check report calculations using records %s' %
               self._records)
        return ['ortho', 'check', 'results']


class QAQCReport(AbstractReport):
    """
    QAQC Report class
    """
    _table_fields = ['FLD_X', 'FLD_Y', 'FLD_Z']

    def calc_coords(self):
        """
        calculates coordinates to be written to report table
        """
        print ('special QAQC report calculations using records %s' %
               self._records)
        return ['qaqc', 'report', 'results']


if __name__ == '__main__':
    input_file = r'c:\test\seismic_file.txt'
    records = ['reca', 'recb', 'recc']

    ocr = OrthoCheckReport(input_file, records)
    qqr = QAQCReport(input_file, records)

    ocr.write_table()
    qqr.write_table()

Cuando se ejecuta, este código muestra:

special Orthogonal Check report calculations using records ['reca', 'recb', 'recc']
writes a table using fields ['FLD_A', 'FLD_B', 'FLD_C']
and calculated coords ['ortho', 'check', 'results'] to file seismic_file.txt

special QAQC report calculations using records ['reca', 'recb', 'recc']
writes a table using fields ['FLD_X', 'FLD_Y', 'FLD_Z']
and calculated coords ['qaqc', 'report', 'results'] to file seismic_file.txt

En la jerarquía anterior, el código del método write_table sólo está presente en una de las clases (la clase AbstractReport), pero instancias de las otras clases ( OrthoCheckReport o QAQCReport) aún pueden llamar a dicho método. Esto se debe a que tanto OrthoCheckReport como QAQCReport son "subclases" de la "clase base" AbtractReport y "heredan". Una subclase que hereda de una clase base tiene acceso a todos los métodos y propiedades de la clase base. Esto quiere decir que, independientemente de qué clase se cree arriba, las llamadas a write_report pasarán por el mismo método.

El método calc_coords demuestra lo que ocurre cuando el código de las subclases debe ser diferente al de la clase base. Cada una de las subclases calcula de forma distinta las coordenadas para la tabla, por lo que presentan un código exclusivo. Para garantizarlo, las subclases "sobrecargan" el método calc_coords desde la clase base. Como se ha demostrado anteriormente, la "sobrecarga" en Python es tan sencilla como agregar un método con el mismo nombre a las subclases. Esto significa que aunque el método write_table tiene exactamente el mismo código para todas las clases, cuando llama a calc_coords, sigue una ruta única a través de las subclases. Con ello, la lógica innecesaria (como declaraciones "if" adicionales) se elimina del código, lo que hace que resulte más fluido y fácil de leer.

Para conseguir que una clase herede de otra, simplemente se debe incluir el nombre de la clase base deseada en la declaración de clase:

class OrthoCheckReport(AbstractReport):

Con esto, se garantiza que la inicialización (__init__) de la subclase es la misma que la de la clase base. Si fuera diferente, se debería escribir también un __init__ para las subclases. Consulte la documentación y la ayuda para ver ejemplos.

Utilizar y ofrecer paquetes de código abierto

¿Por qué código abierto?

Python se ha convertido en uno de los lenguajes de programación de código abierto más populares. De esta forma, los usuarios de Python han creado, literalmente, miles de paquetes de código abierto, muchos de los cuales son directamente aplicables a los tipos de operaciones que uno desea en sus aplicaciones. En la caja de herramientas geodésicas, empleamos muchos paquetes de código abierto para propiciar que nuestros clientes logren sus objetivos.

Como ejemplo, tengamos en cuenta una petición habitual del cliente: crear un informe en pdf del análisis realizado en ArcGIS. Resulta que existe un sencillo paquete de código abierto para varias plataformas disponible llamado ReportLab Toolkit, que tiene la capacidad de crear documentos en pdf. Este paquete contiene completas y eficaces capacidades de manipulación de pdf, además de excelente documentación y un tutorial de iniciación. Gracias a este paquete, pudimos escribir informes y datos en documentos pdf con relativa facilidad y en un tiempo de desarrollo total muy breve. Por lo tanto, la próxima vez que reciba una petición, pregúntese si alguien más ha hecho esto antes y busque en Internet antes de sumergirse directamente en su creación.

La importancia de la licencia

Cuando se encuentra un paquete que hace exactamente lo que uno necesita, lo primero que se debe hacer es leer la licencia. Las licencias de código abierto se proporcionan en diferentes formas, y muchas de ellas están escritas para evitar que el código del software pueda "cerrarse". Es extremadamente importante leer la licencia con mucha atención y asegurarse de que se utiliza correctamente el paquete. En el caso de ReportLab Toolkit, la licencia es una forma de licencia Berkeley Software Distribution (comúnmente conocida como licencia "BSD"). Esta licencia es muy permisiva y autoriza a usar el software y distribuirlo en otro software no libre bajo algunas condiciones. Otras licencias no son tan permisivas y se han diseñado para garantizar que el software que usa otro software de código abierto también es de código abierto (por ejemplo, GPL). Familiarícese con los tipos de licencias más comunes para saber qué puede usar de los paquetes de código abierto y cómo.

Aquí se proporciona una útil tabla de licencias: http://en.wikipedia.org/wiki/Comparison_of_free_software_licenses. Otro recurso de utilidad es el sitio www.opensource.org, que contiene información sobre todas las licencias de código abierto.

Ofrecer paquetes de código abierto

En la caja de herramientas geodésicas, hemos incorporado ReportLab Toolkit como subpaquete, lo que significa que hemos ofrecido el código con el nuestro. Aunque podría parecer sencillo hacer referencia a los paquetes de código abierto en código propio, es importante que se incorpore realmente el paquete. Esto permitirá controlar la versión del paquete que se está usando y garantizar que el paquete está disponible en el equipo del cliente. Solicitar al cliente que instale personalmente el paquete es una complicación que debe evitarse. De nuevo, cuando ofrezca un paquete de código abierto con su código, es imperativo que lea la licencia y cumpla con las obligaciones indicadas en ella.

Conclusión

Para proporcionar la funcionalidad en la caja de herramientas geodésicas, elegimos Python como lenguaje de desarrollo. Python y el marco de geoprocesamiento nos han permitido ofrecer la funcionalidad rápidamente y darle el mismo aspecto y funcionamiento que tiene el resto del producto ArcGIS. Con módulos que forman parte de cualquier instalación de Python, hemos creado un conjunto de unittests para garantizar la calidad de nuestro producto en sucesivas entregas de código y peticiones de nuevas funcionalidades. Aprovechamos las capacidades de Python como lenguaje de programación orientado a objetos para reducir la duplicación en nuestra base de código y, por consiguiente, facilitar el mantenimiento del código. Por último, como Python cuenta con una comunidad de código abierto tan extensa, pudimos buscar un paquete de código abierto que redujera nuestro tiempo de desarrollo y nos ayudara a satisfacer las necesidades de los clientes.

Acerca de Integrated Informatics

Integrated Informatics Inc. es una empresa líder de consultoría sobre implementación y desarrollo de sistemas de información geográfica. Fundada en 2002 y con oficinas en Calgary, Alberta, St. John's, Newfoundland y Houston, Texas, proporciona soluciones de administración de datos espaciales y representación cartográfica automatizada a clientes de toda Norteamérica.

Integrated Informatics ofrece servicio desde hace mucho a sus clientes, entre los que se incluyen las principales y más relevantes empresas independientes e integradas de los sectores de la energía, gobiernos provinciales y estatales y compañías de asesoramiento sobre ingeniería y medio ambiente. Tenemos un largo historial en el desarrollo y la implementación de estrategias, sistemas y tecnologías que ayudan a lograr objetivos empresariales y a aumentar el valor corporativo.

Nuestro punto fuerte son las personas. Nuestro equipo se compone de profesionales experimentados de los campos de los sistemas de información geográfica, administración de datos espaciales, gestión de datos de proyectos y desarrollo de aplicaciones, así como de expertos en disciplinas específicas. Contamos entre nuestras filas con expertos en análisis de ciencia geográfica, medio ambiente e ingeniería de canalizaciones. En nuestro entorno de trabajo, promovemos las ideas, la innovación y la implementación a través del desarrollo profesional, la formación continuada, la implicación en la industria y programas de investigación y desarrollo con fondos propios.

Integrated Informatics es partner comercial de Esri de clase Silver Tier International, participa activamente en su programa beta para pruebas globales y forma parte del consejo consultor para el programa SIG en el Southern Alberta Institute of Technology (SAIT). Visítenos en www.integrated-informatics.com o póngase en contacto con nosotros en gis@integrated-informatics.com para obtener más información sobre nuestras exclusivas soluciones.