Carlos Ble

Carlos Ble

I am a professional software developer, I solve problems.

I also teach and mentor developers to build better software.

Developing software since 2001.

Can I help you?

  • Do you need high quality tailor-made software?
  • Need training on TDD, clean code or refactoring?
  • Do you need a technical consultant?
  • May I pair with you to write better code?

Events

Upcoming training courses:

  1. TDD - [en Español] - 6 y 7 Octubre
    Gran Canaria
  2. TDD - [in English] - October 20, 21 & 22
    London, UK
  3. TDD - [en Español] - 29, 30 y 31 de Octubre.
    Madrid, Spain

Conferences:

  1. I'll be at the Agile Testing Days 2014
  2. I'll be at the London Test Gathering Workshops.

Archive for December, 2010



¿Está mi código bien hecho?

En mi opinión, el código está bien hecho si puede ser entendido por un programador tan rápido como este es capaz de leerlo. Si se tiene que parar a pensar, entonces el código tal vez NO esté bien hecho. Está bien hecho si Product Owner, experto en el dominio, lo puede comprender con apenas algunas explicaciones del técnico que se lo está contando.
El código es bueno si no causa problemas de mantenimiento. Esto es: si cuando se produce un bug, se encuentra y se arregla rápidamente (cuestion de segundos o pocos minutos) entonces esta bien hecho. Incluso aunque hemos detectado algún bug (defecto) en el código, esto no significa que sea malo. Puede ser bueno si hemos comprendido y arreglado rápida y sencillamente el problema, ya que código bien hecho no es código perfecto. Un humano no es perfecto y por tanto no puede escribir código perfecto. El artesano escribe buen código.

Aunque estas afirmaciones pueden parecer exageradas o incluso utópicas, la experiencia me va demostrando cada vez más, que todo lo que se aleja de estas bases causa problemas a medio y largo plazo. Cada vez que hemos querido "correr" para poner en producción una nueva funcionalidad y nos hemos saltado a la torera TDD, lo hemos pagado con bugs en producción y código frágil. Afortunadamente no han sido muchas las veces pero lo cuento para insistir que incluso nosotros, que creemos tanto en TDD, a veces nos lo hemos saltado. Y justamente cuando hemos dicho.... "ok, vamos a sacar esta funcionalidad sin hacer TDD y la vamos a tener corriengo para mañana y luego ya refactorizamos. Además la haré yo solo a toda leche y tu haces tal y cual otra cosa mientras", es cuando hemos tenido mil problemas. Por un lado bugs que han llegado a producción, con la consecuente mala experiencia para el usuario. Por otro lado código difícil de mantener. Cuando lo hemos tenido que depurar, hemos tardado tanto en encontrar los fallos y comprenderlos como lo que habiamos tardado en escribir ese código. Llegado ese punto ya estabamos perdiendo dinero. Cuando hemos querido refactorizar el código prácticamente hemos tenido que borrarlo entero y volverlo a hacer. Curiosamente, al rediseñarlo con TDD hemos incluso descubierto más casos no planeados que iban camino de ser tediosos bugs en producción. Está clarísimo que nos ha salido siempre mucho más caro querer correr y reparchear que hacer las cosas de la mejor forma posible desde un inicio.

Otro error que hemos cometido a veces, es usar el código de un spike para producción. Un spike es la típica prueba que haces para comprender cómo funciona una nueva herramienta o API. Por ejemplo nos ha pasado en la integracion con APIs como Twitter o Google Maps. Teníamos que consumir una libreria de terceros sin saber muy bien como funcionaba. Al no conocer el comportamiento no podemos hacer TDD ya que no sabríamos como especificar el comportamiento de un mock o un stub. Entonces te lanzas y haces el spike. Hasta aquí todo bien. El error viene cuando el spike parece funcionar y entonces lo pruebas un poco a mano y lo subes a producción. Esto nos ha causado los mismos problemas que comentaba antes. Ahora cada vez que hacemos un spike, comprendemos el problema y entonces podemos diseñar cuidadosamente (con especificaciones como siempre) y estar seguros de que cada bloque que escribimos hace lo que tiene que hacer.

Siempre que nos hemos saltado el principio de responsabilidad única (SRP) lo hemos pagado. Especialmente cuando en el código del controlador acabamos poniendo reglas de negocio. En un principio nos lo permitimos porque estas reglas son validaciones del input del usuario pero.... es que al final esas validaciones son muy importantes!!! Nuestra arquitectura ideal en la web es la que comentaba en un post anterior. Cada vez que el controlador contiene más negocio del que debiera (y debiera tener cero negocio) encontramos problemas de mantenimiento.

Cuando uno se sienta a escribir código, no puede tener prisa. Debe tener concentración. Prisa y concentración son dificiles de conseguir a la vez. Lo más probable es que se produzca ansiedad en tal caso. La falsa sensación de que puedes ir rápido y escribir buen código es una fuente de problemas. Las cosas bien hechas no se pueden llevar a cabo en dos dias. Esto de llegar un fin de semana, sentarse 2 amigos y hacer una aplicación, no puede producir código bien hecho. Puede estar bien como prototipo, para mostrar una idea, pero desde luego no es código que yo quiera mantener ni evolucionar.

El hecho de invertir mi propio dinero en mis desarrollos ha sido lo que me ha llevado a querer pisar el acelerador en algunos casos, algo que sucede a muchos dueños de producto. Sin embargo, en términos monetarios, hemos salido perdiendo siempre que hemos hecho esto.
Por otra parte, uno no se puede sentar a escribir código y estar entretenido con un método eternamente hasta que le parece el mejor código del mundo. El trabajo del artesano debe ser fluido, sin prisa pero sin pausa. Con atención al trabajo pero sin perseguir la perfección. No hay que detenerse a hacer refactoring hasta la saciedad. A veces uno escribe código que sabe que no es el mejor, pero en ese momento no tiene la lucidez para mejorarlo. La experiencia te muestra tus propias limitaciones y debes aceptarlas. Aceptarlas significa que en algún lugar anotarás que quieres mejorar ese código y que tan pronto como te sea posible lo harás, seguramente desde que añadas un poco más de funcionalidad a ese bloque. Y "tan pronto como sea posible" será literalmente verdad.

Ser artesano implica ser disciplinado. Pero nadie puede ser disclinado durante 40 horas a la semana, todas las semanas durante 11 meses al año. Con esto voy a que no se puede escribir código bueno cuando se trabaja demasiadas horas. Personalmente encuentro que a partir de las 6 horas, la calidad de mi código disminuye y mi interes por ello también. Nunca compraría código de una empresa que tiene a sus empleados trabajando 10 horas al día, como ocurre en tantas empresas que conozco.

Conforme adquiero experiencia, me doy cuenta de que las demás practicas de XP, son tan importantes como TDD. Programar en pareja, revisar el código de los demás, integrar frecuentemente... Estoy empezando a pensar que las empresas en que nunca se hace programación en pareja, no tienen la madurez suficiente para hacer buenos productos software. Bueno, yo al menos no pagaría por ellos.

Kent Beck, Robert Martin, Martin Fowler, Steve Freeman y tantos otros profesionales, no nos están contando mentiras para vender libros. No están exagerando. Esta es mi impresión sobre el desarrollo de software, cada vez más.

Cada cual es libre de escribir el código como quiera, sobre todo si es open source, pero que nadie se engañe... ningún programador es perfecto. ¿y tu? ¿eres artesano? :-)

So you are getting wrong symbols in your webpage, maybe missing some chars or you are getting this runtime exceptions:

  • TypeError: decoding Unicode is not supported
  • UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128)

And you definitively don't understand why. It is time to learn how to fix it forever!

The information in this post might not be precise but it is short and direct for you to understand at least as I do. Because you don't want to read all those unicode howtos, do you?  (but you should!)

----------------------------------

Python supports the string type and the unicode type. A string is a sequence of chars while a unicode is a sequence of "pointers". The unicode is an in-memory representation of the sequence and every symbol on it is not a char but a number (in hex format) intended to select a char in a map. So a unicode var does not have encoding because it does not contain chars.

Why is encoding needed? In order to print text or write text to a file, you can not write unicode because it would be a  sequence of hex numbers. You have to replace those hex number by chars. The way you choose to do that conversion is the encoding. You can use the ASCII "alphabet" to encode the unicode, or can use UTF-8, etc. The problem is that ASCII is not enough rich to express some symbols like 'ñáéíóú'. You need UTF-8 to encode that unicode string because otherwise, you will miss some chars.

Python manages the string type as a sequence of chars encoded in UTF-8. I guess it should be possible to tell python to encode strings in other ways but all the installations I've seen work like this. So if you work all the time with string types, not mixing them with unicode types, everything will work perfectly and you will have no problems at all. However this is not always possible.If you want to write into a file you have to encode the text. Same if you want to send html to the browser. Both, the file and the browser need chars, not a sequence of numbers so encoding is needed.

Django for example, gives you all the variables sent by http as unicode variables.  This means that using request.POST or request.GET you will get unicode variables. From this point you can start mixing unicode variables with string variables without noticing, until you start getting runtime exceptions as above. Django also uses unicode when it retrieves data from database with the ORM.

To avoid problems you should either, work with strings all the time or work with unicode all the time. If you use unicode all the time, Django will know how to render html by using the DEFAULT_CHARSET setting (default to UTF-8) . I've decided to work with unicode all the time.

Now some unicode management statements:

x = "hello"  # this is a string
y = u"hello" # this is unicode built from the default encoding
z = unicode("hello", 'utf-8') # this is unicode built from utf-8 encoding

Notice that if the default charset is 'utf-8', both y and z will be the same. Otherwise they will be different. A way to express the encoding in python code is using this line at the beginning of the file:

# -*- coding: utf-8 -*-

When I say "built from utf-8 encoding" I mean that in order for the system to recognize which chars you are processing it needs to know how were they encoded.

h = x.decode('utf-8') # this is unicode built from utf-8
j = y.encode('utf-8') # this is a string encoded using utf-8

decode is the way to transform a string in unicode. encode is the opposite.

a = "adiós" # a string containing non-ascii chars
unicode(a) # this raises exception

When you try to convert a string into unicode, you can pass in the encoding or not. If you don't do it, python will try ASCII encoding. As the variable 'a' contains non-ascii chars, it is not possible to encode properly and it raises an exception. This behaviour can be changed with another optional parameter:

unicode(a, errors='ignore') # this produces "adis"

But if the string would have contained just ascii char, this would have worked and you wouldn't notice. If you don't pay attention to this you end up with runtime exceptions faced by your users.

Best practices are:

  1. Always define string literals as unicode sequences:  x = u"some_constant"
  2. Join strings with the % operator:
    joined = u"whatever=%s,ok=%s" % (the_value, the_other_value)
  3. Don't think that a char is always a byte. Some chars need 2 bytes so avoid things like:
    third_char = some_string[3]
  4. Don't cast unicode to string with the str funcion (use decode):
    my_hopefully_str = str(some_var)
    If some_var is unicode, str with try to encode using ASCII and that will raise an exception if it contains non-ascii chars. str function is nice to serialize objects even if they contain non-ascii chars because it will serialize hex numbers.
  5. Don't compare string to unicode:
    "adiós" is not equal to u"adiós"
  6. Some functions are not able to work with unicode because they need chars:
    hashlib.md5(my_string).hexdigest()
    base64.b64encode(my_string)
    urllib.urlencode(dictionary_containting_unicode_values)
    These two functions need a string. Make sure you encode the unicode to the string before calling all these methods. If you pass in unicode, they will try to use ASCII encoding to transform them into string.
    Python SimpleCookie object can't work with unicode either. So when you set cookies like this:
    request.COOKIES[k] = v # v has to be a string, not unicode.
    Same when you use the 'set_cookies' method.
    If you pass in unicode you will get this exception: translate() takes exactly one argument (2 given)

When you make a string or unicode joining variables like this:

x = var1 + "_" + var2

If var1 or var2 is unicode, the system will try to decode all other parts. Remember than decoding a string which contains non-ascii chars is not funny. Joining with the % operator is the same but the sintax makes you aware of the problem because you are writing that 'u' at the beginning.

Here you go some utility functions to use when you want to make sure that a variable is a string or that is is unicode:

  1. # -*- coding: utf-8 -*-
  2.  
  3. def __if_number_get_string(number):
  4. converted_str = number
  5. if isinstance(number, int) or \
  6. isinstance(number, float):
  7. converted_str = str(number)
  8. return converted_str
  9.  
  10. def get_unicode(strOrUnicode, encoding='utf-8'):
  11. strOrUnicode = __if_number_get_string(strOrUnicode)
  12. if isinstance(strOrUnicode, unicode):
  13. return strOrUnicode
  14. return unicode(strOrUnicode, encoding, errors='ignore')
  15.  
  16. def get_string(strOrUnicode, encoding='utf-8'):
  17. strOrUnicode = __if_number_get_string(strOrUnicode)
  18. if isinstance(strOrUnicode, unicode):
  19. return strOrUnicode.encode(encoding)
  20. return strOrUnicode

I don't know the historical reasons to work with unicode types because string types with the chars encoded as UTF-8 is very powerful and free of surprises. Maybe it is because some human languages don't fit into UTF-8. However this is the way it is nowdays.

Necesitamos expert@ en front-end

Hola!
Publiqué en twitter que necesitamos alguna o algun experto en front-end, especialmente optimización de css, imágenes y html. Como ha habido muchas respuesta pongo por aquí nuestra problemática.
Basicamente necesitamos refactorizar muchisimo la css y tambien las imagenes
de la web cuyo banner teneis arriba del todo de este blog.
La version en produccion de ahora mismo, incluso da algunos problemas en IE7.

La cuestion es que maven.css tienes mas de 2000 lineas con un monton de elementos duplicados, nombres inadecuados y se nos hace muy dificil tocar la css sin romper paginas. La maquetamos entre desarrolladores, sin ningun experto y logicamente lo estamos pagando. Por eso ahora buscamos a un verdadero experto, no a cualquiera que haga sus pinitos con css como nosotros.

Ademas la web carga super lentiiisima en IE y esto nos preocupa. Sabemos que se puede optimizar el tema de las imágenes, teniendo una sola imagen que contiene todos los elementos y luego cargandolos como un mapa y cosas asi, pero no podemos dedicarnos a ello.

Buscamos alguien que navegue por TODAS las paginas de la web y nos arregle maven.css y todos los html de por ahi que contienen los estilos puestos ahi al fuego. Vamos, super chungo como está ahora. Tenemos estilos metidos al fuego en determinadas paginas para sobreescribir la hoja de estilos y guarradas asi.

Nos gustaria tener garantías  de que los cambios en css no romperian funcionalidad en ninguno de los navegadores, IE7+, Firefox, Safari, y Opera, entre otros. Para ello sería conveniente conocer un poco jquery. No hce falta escribir nada en jquery sino solo tener cuidado de no romper lo que ya existe, lo cual implica saber que cambiarle el id a un div puede romper el javascript.

Muchas gracias!

Tour 2011

Ultima actualización: 6 diciembre 2010

En mi encuentro con Enrique Comba (@ecomba) durante el coderetreat que hubo en Donosti a finales de 2010, tuve la oportunidad de escucharle un montón de ideas interesantes (gracias Enrique!).  Una de ellas fue la del "ecomba Tour", inspirado en la experiencia de Corey Haines. Hace algún tiempo, Corey decidió recorrer todo su país con su coche programando durante 2 días en empresas que deseasen aprender con él. A cambio de alojamiento y gastos de viaje, Corey se dedicó a viajar de una empresa a otra a lo largo y ancho de todo el país, entrenando a desarrolladores y equipos de todas clases. Tuvo tanto reclamo que la experiencia le duró un año entero.

Para este 2011 he decidido hacer algo "parecido". Me ofrezco a ir a trabajar a tu empresa durante 2 días sin más gastos que el viaje y la estancia. Y la estancia no tiene por qué ser un sitio caro, me vale la casa de alguien que tenga una habitación libre y limpia.

¿Qué ganas con dos días de mi trabajo?
Logicamente no se trata de que vaya dos días a intentar terminar esa release a la que ya no llegas a tiempo. No voy a tu empresa para sacarte el trabajo en dos días, sobre todo porque es imposible. No tengo poderes de super héroe.
El objetivo es enseñar a los desarrolladores mejores formas de trabajar y/o resolver problemas puntuales. Durante estos dos días me sentaré a programar en pareja con varios desarrolladores de un mismo equipo. Practicaremos TDD para desarrollar una tarea nueva que haya pendiente y que sea suficientemente pequeña para que la podamos completar en este tiempo. De manera alternativa podemos hacer refactoring de algún código legado. Podemos buscar por qué ese código está causando tantos problemas o tratar de reducir las largas sesiones de depuración de errores. En ambos casos practicaremos eXtreme Programming y nos ayudaremos de Kanban para la gestión de las pequeñas tareas.

¿Qué tienes que hacer para solicitar mi vista a tu empresa?
Lo primero es entender a lo que voy, entender el valor que puedo aportar. Debes estar convencido de que los métodos ágiles ayudarán al desarrollo de tus productos. Acepto que algunos desarrolladores del equipo tengan reticencia pero la directiva no debe tenerla ya que yo no soy un comercial que vaya a venderle la moto ágil. No necesariamente toda la directiva debe de ser "pro-agil" pero al menos los miembros con poder de decisión que contacten conmigo, sí. Lo demás vendrá poco a poco.
Lo segundo es inscribirse lo antes posible para tratar de planificar la agenda (envíame un email contándome por qué quereis que vaya a vuestra empresa). Tendrán prioridad aquellas empresas que estén en ciudades donde tenga que ir a impartir algún curso de TDD o a hacer algun trabajo de consultoría. Por supuesto las empresas que me contraten un curso de TDD de dos días pueden contar con esta sesión de trabajo de otros dos días si lo desean.
A diferencia de Corey, yo no viajaré constantemente sino que haré una o dos salidas al mes. Si dos empresas situadas cerca se ponen de acuerdo, será más fácil que pueda visitarlas en el mismo viaje.
Despues de los dos días, la empresa dispone de un tercer dia opcional para organizar un coding dojo o code retreat en sus instalaciones, abierto a toda persona que quiera asistir. Este tercer día está sujeto a mi disponibilidad.

¿Qué gano yo con estas sesiones?
Por un lado aprendo mucho de lo que veo en otros sitios. Tanto a nivel personal como a nivel tecnológico (frameworks, herramientas, etc). Por otro lado, estoy haciendo clientes. Las empresas que queden satisfechas con estas sesiones pueden volverme a llamar para entrenar a otros equipos o continuar algun desarrollo, esta vez ya incluyendo mis honorarios. A partir de esta sesión se abren muchas vias de colaboración con estas empresas y de paso, fomentamos el desarrollo de XP en nuestro país.

Si eres empleado sin poder de decisión pero te gustaría que visitase tu empresa, debes conseguir que alguien con poder de decisión sea quien me invite a ir a ella. No puedo aceptar invitaciones de empresas que no entiendan el propósito de mi visita.

Si quieres inscribir a tu empresa, envíame un email hablándome sobre ella. Estoy muy interesado en visitar empresas que tengan ganas de mejorar, de desarrollar productos de más calidad con espíritu de autosuperación.

Este post podrá ser actualizado conforme vaya recibiendo y respondiendo preguntas.  Gracias por tu interés ;-)