developer.cl desarrollo, gestión y otras cosas acerca de proyectos de software

12nov/11Off

Flask, micro framework web

Publicado por lcruz

Hace un tiempo que vengo utilizando Flask como framework, periodo que coincide con mi retorno a desarrollar después de un largo rato.   Mis primeras impresiones fueron bastante favorables, y creo que entre las principales causas estaban su sencillez y buena documentación ideal para superar mi abstinencia de desarrollo.

Flask se describe como un micro framework y para sustentar este extraño nombre que mejor que analizar las decisiones que se tomaron al diseñar el framework entre las que destacan manter la simplicidad en el desarrollo y no tomar muchas decisiones por el desarrollador que en lo concreto se traduce en un kit de herramientas que incluye muy pocas cosas, y aunque esto último parece a primera vista ser algo negativo en la práctica no lo es.

Se incluyen dentro del framework una excelente linea base de funcionalidades que están presentes dentro de la mayoría de nuestros desarrollos como son enrutamiento, manejo de plantillas, manejo de errores HTTP, testing, entre otras además incluye un herramienta de depuración que permite acceder a un shell Python cuando se presentan los problemas.

Si bien las cosas que se incluyen por defecto son pocas es posible extender Flask y para ello dentro del mismo sitio podemos encontrar extensiones para trabajar con base de datos, administración, OpenId, forms y muchas otras.

Los pilares de Flask son dos herramientas ampliamente utilizadas: Werkzeug y Jinga2, el primero es una librería WSGI el estándar Python para comunicar frameworks y servidores Web, el segundo es un motor para manejar plantillas de alto rendimiento que según benckmarks sería mejor que el que incluye DJango.

La simplicidad del framwork se puede observar desde el primer ejemplo:

from flask import Flask
app = Flask(__name__)
 
@app.route('/')
def index():
    return 'Index Page'
 
@app.route('/hello')
def hello():
    return 'Hello World'
 
if __name__ == "__main__":
    app.run()

A primera vista una de las cosas que destacan es el enrutamiento el cuál esta basado en decoradores lo que hace muy fácil de entender el código. Otro punto es la ausencia del contexto request en las vistas, esto se debe a que existe una instancia global del objeto request la cuál esta asociada al hilo de ejecución de nuestra aplicación mediante la utilización de ThreadLocal, esto si bien presenta algunos inconveniente la mayoría de nuestras aplicaciones trabajara sin problemas con esto.

7nov/11Off

Encuentro Linux y Startechconf

Publicado por lcruz

Las últimas semanas han sucedido dos eventos que me han tenido del todo entretenido, El Encuentro Linux 2011 y la Startechconf.   En ambos he participado de distinta forma pero de ambos he rescatado grandes cosas que me hacen estar contento y esperar con ansia las próximos próximas versiones.

En el Encuentro Linux 2011 me toco participar como charlista, junto a @felipeDev expusimos nuestro tema "Desarrollo Ágil de Aplicaciones Móviles".   Esta experiencia fue de un crecimiento personal enorma ya que jamás antes había dado una charla en un evento, desde el minuto de la postulación aprendes ya que debes resumir el tema en poca lineas para presentarlo al equipo a cargo de evaluar si tu charla merece la pena estar.   Lo que siguió después fue un periodo de intenso nerviosismo ya que la charla implicaba no solo dominar el tema sino que presentarlo de una forma que fuera comprensible a un público para mi desconocido.   En lo personal tuve que ensayar y tratar de corregir mi modulación y mi presentación sufrió ajustes hasta el último minuto.

Junto a otros charlistas

Desde mi llegada a Puerto Montt la diversion comenzó al compartir con un grupo humano de primer nivel en una organización impecable, me toco conocer a personas interesantes no sólo en los aspectos técnicos, pude acompañar y disfrutar del resto de las charlas.  El tan esperado momento de mi charla llego y con él vino un relajo y al final salió todo excelente.

En Startechconf me toco estar del lado opuesto, como asistente puede empaparme de los conocimientos que entregaron unos charlistas de primer nivel, fue una tremenda conferencia y se noto el gran esfuerzo que puso el equipo organizador.   Los charlas mostraron temas tan interesantes como CCS3, HTML5, Ruby, Lean Startup entre muchos otros.

Junto a Stephanie Sullivan experta en CCS3

Ha pasado un mes desde que deje mi vida de asalariado pero la libertad que me ha dado este nuevo periodo me ha permitido retomar mis grandes pasiones y aunque es muy temprano para evaluar mi decisión desde el punto de vista economico debo decir que en lo personal me siento creciendo por primera vez desde hace mucho tiempo, entonces la invitación es a participar de la comunidad y aprovechar la gran cantidad que hoy existe de interactuar y aprender, de seguro se sentirán tan afortunados como yo me siento hoy.

25sep/11Off

Django con Admin MultiSite

Publicado por lcruz

Tengo que implementar una aplicación que requiere la administración autónoma de datos por cliente, revisando el administrador de DJango encontré que soporta la administración de múltiples sitios pero requiere de algunos ajustes para que los usuarios no vean los datos entre si.

Lo primero y más fácil es incluir como llave foránea el modelo site a nuestros modelos:

from django.contrib.sites.models import Site
 
class Empresa(models.Model):
    site = models.ForeignKey(Site)
    nombre = models.CharField(max_length=100)

Ahora modificamos el admin para que elimine la selección del sitio y se grabe automáticamente el sitio asociado al usuario que  autenticado:

class EmpresaAdmin(admin.ModelAdmin):
    exclude = ['site']
 
    def save_model(self, request, obj, form, change):
        obj.site = Site.objects.get(pk=setting.SITE_ID)
        obj.save()

Además filtramos los datos para que se muestren sólo aquellos datos asociados al usuario autenticado.

def queryset(self, request):
    qs = super(EmpresaAdmin, self).queryset(request)
 
    if request.user.is_superuser:
        return qs
 
    return qs.filter(site__pk=settings.SITE_ID)

Lo anterior se repite con cada modelo que quieras multi "sitio". Hasta aquí funciona más o menos la cosa, y que SITE_ID es una variable en “duro” y lo que nos interesaría es modificarla por cada usuario que se autentica o en base al dominio consultado, yo optare por la segunda opción, para ello modificare el archivo settings.py:

cambiar la linea:

SITE_ID = 1

por:

SITE_ID = SiteIDHook()

Ahora tenemos que definir la clase SiteIDHook como sigue:

from threading import local
 
SITE_THREAD_INFO = local()
 
class SiteIDHook:
 
    def __int__(self):
        try:
            return SITE_THREAD_INFO.SITE_ID
        except AttributeError:
            SITE_THREAD_INFO.SITE_ID = 1
        return SITE_THREAD_INFO.SITE_ID
 
    def __hash__(self):
        return self.__int__()
 
    def get(self):
        return SITE_THREAD_INFO.SITE_ID
 
    def set(self, value):
        SITE_THREAD_INFO.SITE_ID = value

La información del sitio ahora se almacena en una variable del thread local, ahora sólo tenemos que cambiar el valor de esta variable de forma dinamica para ello creamos un nuevo middleware:

import settings
 
class SiteDetectionMiddleware:
 
    def process_request(self, request):
    ### Aquí alguna lógica para detectar el sitio ###
    ### por ahora sólo estableceré un valor en duro ###
    settings.SITE_ID.set(1)
 
Registramos el nuevo middleware:
 
MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'auth.middleware.SiteDetectionMiddleware',    # Se agrega esta linea
)

Por último me interesa que los usuarios se autentiquen con su correo, así deseo que se de la impresión de que no se repiten los nombres de usuario para cada cliente, para ello creare un archivo el archivo auth/backends.py con el siguiente código:

class SiteDomainModelBackend(ModelBackend):
 
    def authenticate(self, username=None, password=None):
 
        if '@' in username:
            kwargs = {'email': username}
 
        else:
            kwargs = {'username': username}
 
        try:
            user = User.objects.get(**kwargs)
            if user.check_password(password):
                return user
        except User.DoesNotExist:
            return None

Y registramos el nuevo backend:

AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.ModelBackend',
    'proyecto.auth.backends.SiteDomainModelBackend',
)

Y bueno ya tenemos el administrador multi sitio salvo por un problema: el modelo usuario, aunque existe la posibilidad de extender el modelo y agregar la llave hacia el modelo "Site" se debe modificar algunas cosas para que tome por defecto la nueva clase, esto me ha dado algunos problemas y no lo tengo resuelto aún.

Pueden revisar los siguientes enlaces que tome como referencia y tienen algunos de estos ejemplos:
Documentación en DJango para múltiples sitios
Extending the django user model with inheritance
Doing more with the Django admin
Add a button to Django admin to login as a user

13ene/11Off

Lista de deseos

Publicado por lcruz

Comienza el año y vienen las reflexiones sobre el año que dejamos atrás, cosas que hicimos y los momentos gratos que tuvimos, en todo ámbito.   Vienen también los buenos deseos, las metas y objetivos que cumpliremos este año que inicia.

El último cuarto del año que paso estuvo lleno de cosas nuevas, las reuniones organizadas por un grupo de entusiastas chilenos que emergen del ya cansado, temeroso y muchas veces vendido mundillo informático nacional me han hecho entusiasmarme, recuperar esta pasión por desarrollar aplicaciones y aprender nuevas cosas, sentir que hay vida inteligente allá afuera, que hay esperanza por sobre las grandes corporaciones y por sobre la desidia y mediocridad imperante en el medio.

Claro quedan muchas cosas por aprender, todo esta cambiando y si quieres ser parte del mercado en los próximos años no te queda otra alternativa que cambiar también, razones existen muchas pero te invito a hacerlo simplemente por gusto, por diversión, el resto llegará sólo.

Yo por mi parte aquí dejo algunas de las cosas que me gustaría aprender este año, la lista esta incompleta en absoluto pero espero ir llenándola en el transcurso de las próximas semanas y volveré a ella a través de todo el año y espero tachar todos los conceptos en ella o al menos la mayoría, se viene un año lleno de desafíos y diversión, espero se atrevan a acompañarme en tan entretenido desafío.

Lista de deseos 2011:

  1. Aprender OpenID y todas las apis de autenticación
  2. Aprender FubuMVC para enseñarles algo interesante a los programadores .NET en la pega
  3. Retomar Ruby on rails para no perderme en los meetups
  4. Aprender GIT
  5. Aprender Jython para utilizar el poder de java con python
  6. CoffeScript por que se ve bueno :D
  7. Spring
  8. Appclerator Titanium
  9. Hadoop
  10. Tocar guitarra de una vez
  11. Hablar en inglés (bien)
24dic/10Off

Implementando autenticación con DJango+Google

Publicado por lcruz

He estado jugando estos días con la implementación de Google para autenticar sitios Web, por alguna razón no se me hizo fácil al principio pero después de leer un rato y averiguar más ya hay humo blanco, es de esas cosas que al principio las encuentras complejas y luego te das cuenta que no podía ser más fácil, como siempre gracias a la comunidad mediante librerías que facilitan el trabajo.

Google basa su API en el estandar OpenID que brinda métodos descentralizados de autenticación, permitiendos entre otras cosas autenticarnos a múltiples sitios utilizando las mismas credenciales.   A modo general el esquema OpenID se compone de tres elementos principales: El proveedor de OpenID, que es quien nos facilita el servicio de autenticación,  el Relying Party, que vendría siendo el tercero o quien quiera autenticar a un usuario, y por último se encuentra el usuario.

En mi caso yo estoy realizando como ejemplo un sitio Web que necesita autenticar a usuarios, pero no quiero crear mi propio registro de usuarios y sistema de autenticación, en su lugar voy a utilizar a Google como proveedor OpenID.   La implementación la estoy realizando DJango y me he bajado la librería django-openid-auth.   Existen varias otras pero es la que he encontrado más sencilla y funcional.

Una de las primeras cosas que realice fue registrar el dominio en Google, no estoy seguro si es requerido para utilizar los servicios de autenticación pero en mi caso deseo utilizar otros servicios  futuro que si requieren una autorización de domino para comenzar a operar como GMail o Google Calendars.

Cuando te bajas las librerías de django-openid-auth, la cosa se vuelve casi monótona, claro y si es así te preguntaras porqué lo escribo... bueno una vez que entiendes es fácil pero hay varias cosas que pasan por debajo que es mejor comprender.

Lo primero es presentarle la aplicación a DJango, para ello la inscribimos dentro de las aplicaciones instaladas en el archivo settings.py:

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django_openid_auth',
)

Luego nos corresponde agregar un Backend especial para que DJango pueda realizar la autenticación con OpenID. Los Backend le informan a DJango o más bien implementan la lógica propia del proceso de autenticación, por ejemplo el backend estándar es manejado por DJango contra una base de datos utilizando el modelo User.

# Nada de esto existe, así que debemos agregar todo el codigo
AUTHENTICATION_BACKENDS = (
    'django_openid_auth.auth.OpenIDBackend',
    'django.contrib.auth.backends.ModelBackend',
)

Cuando un usuario nuevo llega a registrase a nuestro sitio, DJango intentará autenticar al usuario utilizando OpenIDBackend, como la autenticación y el registro de usuarios son dos cosas diferentes DJango arrojará un error indicándonos que el usuario no existe, una forma de solucionar este detalle es agregar la siguiente línea para que DJango cree automáticamente los usuarios:

OPENID_CREATE_USERS = True

Esta última línea unida al OpenIDBackend me molesta particularmente ya que en mi caso particular quería crear una autenticación independiente a la de DJango, esto me creará a los usuarios que se registren como usuarios entandar en DJango.

Lo siguiente es decirle a nuestra implementación que actualice los datos del usuarios DJango con los que encuentre en el proveedor OpenID, esto dependerá de cada proveedor pero hay algunos datos básicos que nos entrega la implementación de Google como son el correo y el nombre del usuario. Si queremos que esto suceda de forma automática agregamos lo siguiente:

OPENID_UPDATE_DETAILS_FROM_SREG = True

Configuramos la página de retorno para cuando el proceso de autenticación termine:

LOGIN_REDIRECT_URL = '/'

Por último informamos la URL de nuestro proveedor OpenID:

OPENID_SSO_SERVER_URL = 'https://www.google.com/accounts/o8/id'
22jun/09Off

Extendiendo manage.py para sincornizar con Flex

Publicado por lcruz

Estamos haciendo un sistema que tendrá como interfaces algunas pantallas en Flex por lo que ha surgido la necesidad de publicar algunos servicios remotos utilizando PyAMF. En Flex utilizamos Cairngorm como MVC, este requiere la definición de un archivo de servicios Services.xml que estoy intendando generar utilizando Python y que mejor que hacerlo utilizando el mismo estilo que utiliza DJango para la sincronización de la base de datos. Por ello estoy intenando generar una opción nueva el comando manage.py de la aplicación DJango:

manage.py syncflex

Gracias a la flexibilidad de DJango esto es bastante fácil nada más debes crear una clase que debes llamar Command que extienda a la clase BaseCommand y ubicarla en paquete managment/commands bajo alguna de tus aplicaciones en mi caso yo estoy haciendo un pequeño ERP así que la ubique en la ruta flex/managment/commands:

Arbol de Proyectos

En mi caso dado que mi comando no tiene argumentos extendere la clase NoArgsCommand :

class Command(NoArgsCommand):
 
    help = "Sync Flex Commands"
    requires_model_validation = False    
 
    def handle_noargs(self, **options):
 
        # Your code here

El método handle_noargs es el que nos permite ejecutar las acciones realizadas por nuestro comando cuando es invocado, en mi caso la implementación es la siguiente (algo básica por ahora):

def handle_noargs(self, **options):
 
        from pyamf.remoting.gateway.django import DjangoGateway
 
        import sys
 
        project = settings.ROOT_URLCONF.split('.')[0]
 
 
        #import types
        for app in models.get_apps():
            if project == app.__name__.split('.')[0]:
                app_name = app.__name__.split('.')[-2]
                package = project + '.' + app_name  + '.gateway'
                try:
                    mod = __import__(package, globals(), locals(), ['gateway'], -1)
                    for d in dir(mod):
                        attr = getattr(mod, d)
                        try:
 
                            if isinstance(attr, DjangoGateway):
                               self.processClass(d, attr)
 
                        except TypeError:
                            pass
                except ImportError:
                    pass

Como se puede ver su funcionamiento se basa en introspección, para ello busco un módulo llamado gateway dentro de mis aplicaciones DJango una vez que encuentro el módulo busco en él las clases que extiendan a DjangoGateway para generar el archivo Services.xml. Un ejemplo de mi archivo gateway.py es:

from pyamf.remoting.gateway.django import DjangoGateway
from django.contrib.auth.models import User
from sampleapp.contabilidad.models import Comprobante
from sampleapp.gateway.amf import AMFGateway 
 
class ComprobanteGateway(AMFGateway):
 
    def obtenerComprobantes(self, request, data):     
       # Implemetnar
       pass           
 
class CuentaGateway(AMFGateway):
 
    def obtenerCuentas(self, request, data):     
       # Implemetnar
       pass
 
contabilidadGateway = DjangoGateway({'gwComprobante' : ComprobanteGateway, 'gwCuenta' : CuentaGateway,})

Si vemos la implementación del método processClass tenemos lo siguiente:

def processClass(self, name, gateway):     
        import inspect   
 
        print ("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
               "<cairngorm:ServiceLocator xmlns:mx=\"http://www.adobe.com/2006/mxml\""
               "xmlns:cairngorm=\"com.adobe.cairngorm.business.*\">\n")  
        for g in gateway.services:
            print ("<mx:RemoteObject id=\"" + g + "\" "
                   "\n\t\tdestination=\"" + g + "\" "
                   "\n\t\tendpoint=\"" + settings.REMOTING_URL +  "/" + name + "\" "
                   "\n\t\tshowBusyCursor=\"true\" " 
                   "\n\t\tresult=\"event.token.resultHandler( event );\" " 
                   "\n\t\tfault=\"event.token.faultHandler( event );\">")
 
            service = gateway.services[g]            
            for m in service.getMethods():
                print "\t<mx:method name=\"" + m + "\" />" 
            print "</mx:RemoteObject>\n"
 
        print "</cairngorm:ServiceLocator>"

Con eso ya estamos casí listos sólo nos falta agregar nuestra aplicación para que DJango la conozca y definir la variable REMOTING_URL para ello sólo editamos nuestro archivo settings.py:

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.admin',
    'sampleapp.contabilidad',    
    'sampleapp.compra',
    'sampleapp.agricola',
    'sampleapp.rrhh',
    'sampleapp.maquinaria',
    'sampleapp.comun',    
    'sampleapp.actividad',
    'sampleapp.flex',
)
 
# --------------------------------------------------
# My customs settings
# --------------------------------------------------
REMOTING_URL = "http://localhost:8080/remoting"

Con eso ya estamos listo ahora sólo ejecutamos manage.py syncflex en la consola:

 manage.py syncflex

Aquí una muestra del resultado:

<?xml version="1.0" encoding="utf-8"?>
<cairngorm:ServiceLocator xmlns:mx="http://www.adobe.com/2006/mxml"xmlns:cairngorm="com.adobe.cairngorm.business.*">
 
<mx:RemoteObject id="gwCuenta" 
		destination="gwCuenta" 
		endpoint="http://localhost:8080/remoting/contabilidadGateway" 
		showBusyCursor="true" 
		result="event.token.resultHandler( event );" 
		fault="event.token.faultHandler( event );">
	<mx:method name="obtenerCuentas" />
</mx:RemoteObject>
 
<mx:RemoteObject id="gwComprobante" 
		destination="gwComprobante" 
		endpoint="http://localhost:8080/remoting/contabilidadGateway" 
		showBusyCursor="true" 
		result="event.token.resultHandler( event );" 
		fault="event.token.faultHandler( event );">
	<mx:method name="obtenerComprobantes" />
</mx:RemoteObject>
 
</cairngorm:ServiceLocator>
24may/09Off

Complementos de búsqueda con OpenSearch

Publicado por lcruz

Hace poco escribí algunas extensiones utilizando OpenSearch. OpenSearch es un conjunto de estándares que permiten la publicación de los resultados de los sistemas de búsqueda permitiendo de este modo la sindicación y la agregación de contenidos entre diferentes motores y sistema de búsqueda. OpenSearch se compone de 3 partes, un formato para la descripción de motores de búsqueda, un formato para la descripción de los resultados de búsqueda llamado OpenSearch Response y finalmente los agregadores o sitios capaces de mostrar resultados en formato OpenSearch.

Navegadores como IE7 y Firefox soportan ya OpenSearch, es decir, permiten la incorporación de complementos de búsqueda mediante este estándar, al mismo tiempo cada uno de estos navegadores extiende las capacidades estándares de OpenSearch agregándole sus propios sabores.

La utilización de OpenSearch permite incorporar algo de usabilidad a tus sitios Web, si es que, los mismos presentan buscadores a los usuarios. Yo en mi caso particular utilizo un diccionario en inglés de la empresa WordMagic, este diccionario presenta un buscador en su portada mediante el cuál puedes acceder a las palabras del diccionario. Dado que a mí me resultaba bastante molesto ingresar al sitio para realizar la búsqueda es que me decidí a hacer este complemento, además es muy sencillo hacerlo y lo puedes incorporar también en tus sitios. A continuación veremos este ejemplo:

<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/" xmlns:moz="http://www.mozilla.org/2006/browser/search/"> 
    <ShortName>WordMagic</ShortName> 
    <Description>Word Magic Software, Inc. es una compañia dedicada al desarrollo de software con sede en Houston, Texas.</Description> 
    <InputEncoding>UTF-8</InputEncoding> 
    <Image width="16" height="16" type="image/x-icon">http://wordmagicsoft.com/favicon.ico</Image> 
    <Url type="text/html" method="POST" template="http://wordmagicsoft.com/diccionario/search.php"> 
        <Param name="word_to_search" value="{searchTerms}"/> 
        <Param name="search_option" value="es-en"/> 
    </Url> 
</OpenSearchDescription>

Los parámetros especificados son los siguientes:

  • OpenSearchDescription: Este es el nodo principal de un documento OpenSearch.
  • ShortName: Un pequeño titulo que identifique al buscador.
  • Description: Una descripción más larga acerca del buscador.
  • InputEncoding: El encoding que soporta nuestro el buscador.
  • Image: La url de algún icono representativo de nuestro buscador.
  • URL: Describe la interfaz para nuestro buscador, o sea aquella que responderá a las búsquedas. El atributo template permite especificar la url y el atributo method permite indicar si se hará un GET o un POST a la url.

Eso es todo! Guardamos el contenido en un archivo xml, en mi caso le puse wordmagic.xml y ya esta! ahora solo nos queda agregarlo a nuestro navegador, para ello utilizaremos un pequeño javascript, para ello puedes construirte una página con lo siguiente:

<SCRIPT LANGUAGE="JavaScript"> 
<!-- 
    function addWordMagicSearch() { 
        window.sidebar.addSearchEngine("http://developer.cl/opensearch/wordmagic.xml", "http://wordmagicsoft.com/favicon.ico", "WordMagic", ""); 
    } 
//--> 
</SCRIPT>

Luego solo tienes que agregar la llamada en el HTML:

<a href="#" onclick="addWordMagicSearch();">Agregar búsqueda en WordMagic</a>


Mira aquí esta el mio.

8jul/08Off

Twitter, algo útil despues de todo.

Publicado por lcruz

image

Antes pensaba que twitter era una perdida de tiempo ¿para que diablos alguien seguirá a otros en una especie de reality virtual con sólo 140 caracteres por escena?   Ahora lo llevo utilizando una par de días y lo encuentro de una simpleza similar a del.icio.us pero con un potencial de igual magnitud: acceso a información de primera línea, una mirada sobre el hombro de gente que la lleva en determinados temas.   Me quede pensando en esto luego de descubrir Watin ojeando twitter. Con una rápida mirada te enteras del diario vivir de gente que consideras un referente, sin quererlo una especie de consejo, un mini-blog, en fin, una herramienta útil para un aprendiz de Jedi como yo.

8jul/08Off

Watin, mejor que Selenium pero sólo para .NET

Publicado por lcruz

image

Acabo de encontrar a Watin, una herramienta OpenSource para la automatización de pruebas mediante la imitación o grabación de las secuencias de interacción sobre una página Web, según un experto en el tema es mejor que Selenium, al parece su uso es bastante sencillo y soporta Internet Explorer y Firefox.   Lamentablemente sirve solo para aplicaciones .NET, así que por ahora no me queda otra que seguir intentando configurar Selenium.

29jun/08Off

Documentación que entorpece la calidad

Publicado por lcruz

¿Hasta cuando será suficiente documentar el código? Uno de nuestros clientes revisa detenidamente el código fuente en las entregas, o por los menos a primera vista eso parece, sin embargo, me he dado cuenta que el foco principal de la revisión es la documentación del código, esto prosupuesto no tiene nada de extraño ni de malo, pero en mi opinión se ha perdido un aspecto importante de la revisión: la calidad del código entregado.

Cada día me encuentro con código duplicado, extensas funciones y métodos o nulo control de errores, es evidente que las revisiones ponen mas énfasis en la forma que en el fondo, dejando atrás los muchos otros aspectos que hablan acerca de la calidad del software.   Bajo este planteamiento los mejores códigos serán aquellos que están más documentados, sin considerar aspectos como el tamaño, la complejidad de los algoritmos, el uso eficiente de recursos, entre muchas otras cosas.

Hoy en día el escenario global resalta otras metodologías y prácticas, una de ellas es el refactoring, definido de forma simple como la mejora del diseño del código existente, el cuál debido al acoplamiento existente entre la documentación y su código, se ve entorpecido; en cierto sentido la documentación desincentiva la iniciativa de refactorizar poniendo barreras a la mejora.

Es indudable que la documentación del código nos ahorrara varios dolores de cabeza y frustración pero cuando nos nubla la vista y adormece nuestros sentidos es hora de preocuparse.