El blog de Carlos Ble

BrainStream.Write(Posts)

Robert C. Martin rocks

Filed under: Software Development — Carlos Ble at 3:10 pm on Thursday, June 11, 2009

This is nothing new, Uncle Bob rocks we all know that. But... man, you've got to check out these podcasts, they're just impressive.

I am looking forward to buy some Robert's books.

Agile Spain avanza

Filed under: Agile — Carlos Ble at 3:04 pm on Thursday, June 11, 2009

Impresionante el movimiento que está habiendo en Agile Spain últimamente. Prueba de ello es la reciente celebración de Agile Madrid y los podcasts y videos que están ya disponibles para descarga. No tienen desperdicio. Hay que felicitar a JM Beas por toda la energía que está poniendo en la comunidad.
Enlaces:

Que siga así la cosa :-)

Conclusiones del curso de TDD

Filed under: Test Driven Development — Carlos Ble at 8:04 am on Thursday, June 11, 2009

Ayer terminé de impartir mi primer curso de Test Driven Development de 10 horas. Anteriormente habia dado otro de unas 5 horas de duración que me dejó muy buen sabor y tenía ganas de intentarlo con otro más largo. Gracias a J.L. Roda, Pedro González y la Agencia Canaria de Investigación hemos podido montar un curso a modo de taller en la Universidad de La Laguna para un pequeño grupo de 15 intrépidos desarrolladores. El nivel de los asistentes ha sido muy bueno y su actitud también. La gente joven es menos reacia a nuevas metodologías y aunque en sólo 10 horas es muy complicado estudiar un proyecto de software relativamente grande, algunas de las ideas más importantes se asimilaron bien. Ha sido un placer. Espero que en el futuro podamos organizar un curso de mayor duración para abordar un desarrollo mayor y así demostrar que lo que hemos aplicado para un pequeño es exactamente igual para uno grande, aunque les cueste creerlo.
Gracias a todos los asistentes :-)

Ant support: Eclipse wins

Filed under: Software Development — Carlos Ble at 1:16 pm on Wednesday, June 3, 2009

Eclipe or Netbeans? Netbeans is great for the Swing designer, it is my favorite tool for desktop UI design.
However for the rest of the tasks I prefer Eclipse. Eclipse integration with Ant is very good as the editor reads all the dependencies within the buid.xml and provides all the autocompletion just by loading the project (create a new Java project from existing Ant file). Running the JUnit targets from the build.xml works fine which is something I couldn't make with Netbeans. Netbeans didn't find the tests.
Once the project is loaded go to Window menu -> Show view -> Ant. See the Ant view at your right hand side and click on the tiny "Add Buildfiles" button on the top of it. Select the build.xml and you're done.

My JUnit configuration (slightly modified from this post):

 
<path id="classpath.unit_test">
<pathelement location="${lib}/comun/junit-3.8.2.jar" />
<pathelement path="${build.datos}"/>
<pathelement path="${build.cliente}"/>
<pathelement location="./test/unitarios" />
    <fileset dir="${lib.comun}">
        <include name="**/*.jar"/>
    </fileset>
   	<fileset dir="${lib}/cliente">
   	        <include name="**/*.jar"/>
   	</fileset>
   	<fileset dir="${lib}/control">
   	   	        <include name="**/*.jar"/>
   	</fileset>
   </path>
 
    <target name="unit_test.compile" depends="unit_test.clean">
        <javac srcdir="./test/unitarios"
        	   verbose="yes"
        	   includeAntRuntime="true"
        	   debug="on" debuglevel="lines,vars,source">
            <classpath refid="classpath.unit_test"/>
        </javac>
    </target>
    <target name="unit_test.clean">
        <delete verbose="yes">
          <fileset dir="./test/unitarios" includes="**/*.class" />
        </delete>
    </target>
 
    <target name="unit_tests.run" depends="unit_test.compile"
    	description="Run unit tests">
        <junit showoutput="yes"
    	       printsummary="yes"
        	   filtertrace="off" fork="yes"
        	   haltonfailure="no">
           <classpath refid="classpath.unit_test" />
<formatter type="plain"/>
           <batchtest>
            <fileset dir="./test/unitarios/">
              <include name="**/*Tests.class"/>
            </fileset>
          </batchtest>
        </junit>
    </target>
 

Exceptions' stack traces are sent to a file in the project main folder called Test-your_test_case_name.txt
For better output in the Eclipse Console while running the tests, click over the unit_test.run target with the right mouse button (in the Ant view) then "Run as" and then "Ant Build..." and set "-v" in the arguments in the "Main" tab. Note the "debug=on" in the javac target (thanks Nilesh).
The test execution summary is presented for each TestCase rather than altogether so scroll up to watch all
the results (I was wondering why just one TestCase was ran)

Dynamic and Testable wizard with FormWizard and polymorphism

Filed under: Django, Software Development — Carlos Ble at 6:26 pm on Tuesday, May 19, 2009
Very important update: DO NOT USE THE FORMWIZARD for dynamic steps as described below. Django stores the FormWizard as a Singleton so concurrent sessions produce crazy behavior on the wizard. Thanks to my friends at Galotecnia.com because they found the problem. Use the FormWizard just as described in Django documentation and always stateless.

---------------------------
Django FormWizard is really useful. But when it comes to variable steps (I mean, depending on the choosen answer the user gets different forms) you can't just initialize the FormWizard with a bunch of Forms as you don't know which ones. Using polymorphism makes it possible to save lots of code lines by letting each form decide which one is next.

Instead of define your form extending Form, use this base class:

 
class WizardStepForm(forms.Form):
    step_order = 0
    confirmQuestion = "Proceed?"
 
    def process_dynamic_step(self, form_list):
        raise NotImplementedError("Please implement this")
 
    def get_field_name(self):
        raise NotImplementedError("Please implement this")
 
    def get_field_name_for_summary(self):
        fieldname = self.get_field_name()
        firstUpper = fieldname.upper()[0] + fieldname[1:]
        return firstUpper + ":"
 
    def append_end(self, form_list):
        return "", form_list
 

Now we assume our FormWizard will work with WizardStepForms instead of regular Forms:

 
class MyWizard(FormWizard):
    def get_summary(self, form_list):
        """
         To show the user the summary at the last step
        """
        summary = ""
        for i in form_list:
            if hasattr(i, "cleaned_data"):
               if isinstance(i, WizardStepForm):
                  model = i.cleaned_data[i.cleaned_data.keys()[0]]
                  append_text = i.get_field_name_for_summary()
                  append_text = append_text + " " + str(model)
                  summary = summary + append_text + "<br>"
        return summary
 
    def get_hidden_summary(self, form_list):
        """
         Collect the information from all the steps which is in the input hidden field
        """
        summary = ""
        for i in form_list:
            if hasattr(i, "cleaned_data"):
               model = i.cleaned_data[i.cleaned_data.keys()[0]]
               if hasattr(model, "id"):
                   summary  = summary + str(model.id) + ":"
               else:
                   summary = summary + str(model) + ":"
        summary = summary[:-1]
        return summary
 
    def done(self, request, form_list):
        summary = self.get_summary(form_list)
        hidden_summary = self.get_hidden_summary(form_list)
        return render_to_response('confirm.html',
            {
            'summary': summary,
            'hidden_summary': hidden_summary,
            'form': ConfirmationForm(), # a regular Form
            },
            RequestContext(request))
 
    def get_template(self, step):
        return 'wizard.html'
 
    def process_step(self, request, form, step):
        self.extra_context = {'info': ''}
        if hasattr(form, "cleaned_data"):
            info, self.form_list = form.process_dynamic_step(self.form_list)
            self.extra_context = {'info': info}
 

Now two forms for the wizard (two steps):

 
class SearchWhateverForm(WizardStepForm):
    step_order = 1
 
    someChoice = forms.ChoiceField(choices=WHATEVER_CHOICES)
 
    @classmethod
    def get_field_name(self):
        return "whatever"
 
    def process_dynamic_step(self, form_list):
        form_list = form_list[:self.step_order]
        form_list.append(WhatToGenerateForm)
        return "How many items do you need to generate?", form_list
 
class WhatToGenerateForm(WizardStepForm):
    step_order = 2
    generate = forms.ChoiceField(choices=GENERATION_CHOICES)
 
    @classmethod
    def get_field_name(self):
        return "generate"
 
    def process_dynamic_step(self, form_list):
        form_list = form_list[:self.step_order]
        generate = self.cleaned_data['generate']
        if generate == GENERATE_EXACT or generate == GENERATE_EXACT_90:
           form_list.append(HowManyToGenerateForm)
           return "Please set number", form_list
        else:
           return self.append_end(form_list)
 

File urls.py would be like this:

 
  url(r'^wizard/$', MyWizard([SearchWhateverForm])
 

Only one template is needed for all the steps:

 
<form action="." method="post">
<table>
			{{ form }}
		</table>
<input type="hidden" name="{{ step_field }}" value="{{ step0 }}" />
		{{ previous_fields|safe }}
<input class="button" type="submit" value="{% trans "Next Step" %}" />
</form>
 

So, How could you test drive the wizard?

As you don't need views or templates to run the sequence, it is easy:

 
def test_StepsAreOk(self):
        form_list = []
        form_list.append(SearchWhateverForm)
        # define somedata
        form_list[-1].cleaned_data = {SearchWhateverForm.get_field_name(): somedata}
        info, form_list = form_list[-1]().process_dynamic_step(form_list)
        self.assertEqual(form_list[-1].get_field_name(), WhatToGenerateForm.get_field_name())
 

How can I populate the choices of one form dynamically?

The forms_list of the wizard is not populated with instances but data types so you've got to dynamically create a form type once you know which choices will it have available. One solution is to extend from one of your forms:

 
class SomeWizardStepForm(WizardStepForm):
    step_order = 1
 
    #field is not defined
 
    @classmethod
    def get_field_name(self):
        return "whatever"
 
    def process_dynamic_step(self, form_list):
        form_list = form_list[:self.step_order]
        form_list.append(TheNextForm)
        return "whatever", form_list
 
def createDynamicForm(self, someInput):
        class SomeDynamicForm(SomeWizardStepForm):
             field = forms.ModelChoiceField(queryset=someInput.get_whatever())
        return SomeDynamicForm  # returning a datatype not an instance.
 

Method createDynamicForm can be inserted in MyWizard class or in any WizardStepForm, in its process_dynamic_step method, so once the datatype is returned the form_list can hold the new form.

What if I need to populate the first step form with an incoming variable?

Initialize the FormWizard with an empty list:

 
url(r'^wizard/(?P<someInput>\d+)/$', MyWizard([]),
 

Add logic to MyWizard to populate and place the first form:

 
class MyWizard(FormWizard):
 
    someInput = None   # this is a model in my actual code
 
    def _initialize(self, id):
        self.someInput = SomeModel.objects.get(id=id)
        self.extra_context = {'someInput': self.someInput}
        self.form_list = []
        self.form_list.append(self.createDynamicForm(self.someInput))
 
    def parse_params(self, request, *args, **kwargs):
        """
        Get the parameters sent through the URL
        """
        if self.someInput is None:  # first time
           self._initialize(kwargs['someInput'])
 
    ....
 

It the code snippets are not clear enough let me know.

Developers needed

Filed under: Software Development, Uncategorized — Carlos Ble at 10:49 pm on Thursday, May 14, 2009

Do you want to work (part time) on development projects using Django?. We're looking for candidates all over the planet, we'll work over the internet. If you've got:

  • Interest on test driven development and other XP techniques
  • Good english level (at least as bad as mine)
  • Python experience
  • Subversion experience

Django knowledge is also interesting. Remember this is just part time, not any permanent position.
Hackers please send me an email with your CV, or just your blog and your rates. Thanks :-)

Por las mañanas en Novasoft Canarias

Filed under: Software Development — Carlos Ble at 12:17 pm on Saturday, May 9, 2009

He tenido la suerte de entrar en el equipo de desarrollo de Novasoft Canarias en el proyecto de software que usa el Servicio Canario de Empleo. Muy buenas condiciones laborales y muy buen ambiente. La verdad que es una oportunidad estupenda. Esta vez estoy con Java. Ahora toca compaginar mi trabajo en ésta gran empresa con mis colaboraciones particulares con otras empresas que han tenido a bien confiar en mí para desarrollos varios. Se preveen meses de mucho trabajo y nuevos posts sobre cuestiones relativas a Java.

Por cierto, estoy buscando colaboradores con conocimientos en Django, HTML, CSS, y Javascript que puedan trabajar via internet a tiempo parcial. Si alguien esta interesado puede encontrar mi email en el enlace de Contacto.

Profesional Independiente

Filed under: Uncategorized — Carlos Ble at 9:53 am on Friday, April 3, 2009

Se acaba un buen año de trabajo en la Oficina de Software Libre de la ULL. Ha sido un año donde he aprendido muchísimo y disfrutado de muchos buenos momentos. Un jefe excelente, y en general, grandes compañeros. Sin duda ha sido una experiencia profesional y personal muy positiva. El proyecto software que he dirigido está a punto de publicarse y en producción en todos los servidores de las aulas de informática de la Universidad y estoy bastante satisfecho con el resultado. Es un buen momento para el cambio.

Asi que me toca cambiar de rumbo y afrontar nuevos retos. Es hora de ser profesional independiente y colaborar con empresas para proyectos concretos, aportando conocimiento, ideas y trabajo. Desde coordinar a desarrolladores hasta participar como desarrollador de refuerzo o de apoyo en momentos críticos de los proyectos, o llevar el rol de arquitecto. Crisis tambíen significa oportunidad. En ésta nueva etapa la docencia jugará un papel importante porque considero necesaria la difusión del agilismo, particularmente metodologías como eXtreme Programming. Se avecinan varios cursos sobre TDD pronto, ya os daré más detalles.

Si lees ésto y necesitas ayuda para tu empresa o proyecto, o personal para emprender uno nuevo, no dudes en ponerte en contacto conmigo :-)

Pinsor 0.6 released!

Filed under: Software Development — Carlos Ble at 8:00 pm on Sunday, March 29, 2009

I am glad to blog about Pinsor 0.6 release. Pinsor is an Inversion of Control container for Python created by Ryan Svihla. I've started collaborating with Ryan on this release and committed a few changes (not much). It's been nice to talk about design decisions and see that there is a new release after all. Pinsor is useful from now and looks promising for the future.

Soaplib - catch exceptions inside de web service

Filed under: Software Development — Carlos Ble at 11:05 am on Friday, March 20, 2009

We've developed a decorator intended to be placed on top of the "soapmethod" decorator that allows you to catch any exception raised by the web method.

Usage:

 
@catchWsExceptions
@soapmethod(String, _returns=Array(String))
def srv_whatever(self, someParam):
        # just business logic, no exception handling required.
 

Decorator code:

 
import inspect
import traceback
 
def catchWsExceptions(func):
    def wrapped(*args, **kwargs):
        if func.__module__ <> "soaplib.service":
                raise ApplicationException("catchWsExceptions decorator can only be used before soapmethod decorator")
        try:
            result = func(*args, **kwargs)
            return result
        except Exception,  e:
            tb= sys.exc_info()[2]
            tpl = traceback.extract_tb(tb)
            failedCall = str(tpl[-1][0])
            if re.search("soaplib", failedCall):
                Logger.getInstance().logException(e)
                raise # this is not an exception within the function but before calling the actual function
            if type(e) == type(TypeError):
                raise # API mistmach exception should not be filtered
            msg = ""
            if hasattr(e, "message"):
                msg = e.message
            Logger.getInstance().logException(e)
            return ['2', msg + str(e.args)]
    wrapped.__doc__ = func.__doc__
    wrapped.func_name = func.func_name
    wrapped._is_soap_method = True
    return wrapped
 

Logger and ApplicationException belong in our code base but you can just replace them. You may also raise the caught exception rather than return an array with an error code. It is a design decision.

Next Page »
 
Buy commercial air purifiers air purifiers and air ionizers.