soledad penadés
repeat 4[fd 100 rt 90]

Archive for the ‘code’ Category

20070627 Superminigallery: a gallery with ruby, rmagick and builder

Imagine you have been in a very nice place for holidays. You took a lot of pictures and want to show them to your family and friends, but you don't feel like using services like flickr or programs like iPhoto. You just want to put them in your own server and give the url to your friends.

What can you do? Well, you could do like me and create a little script to generate an HTML file, with thumbnails and even watermarked images (just in case some creepy individual decides to use your stuff without asking first).

Superminigallery thumbnail

Requirements

This script requires a couple of gems to be installed: RMagick and builder (but if you've done some stuff with Rails you might already have them). RMagick is used for dealing with the images and builder is used for generating the XHTML. This is because I didn't want to write any html by hand, with their less than and greater than signs, attributes, etc.

Using it

  1. Create a folder in your computer. For example: holidays.
  2. Then you copy there the pictures you want to show to the world.
  3. Open a terminal and cd to that directory. E.g.
    cd ~/Desktop/holidays
  4. Execute the script! E.g.
    ruby ~/code/superminigallery.rb
  5. Wait until it finishes

When it finishes you'll find there's an output folder in the holidays folder. That's where the index.html file, as well as all the thumbnails and watermarked images are. Simply upload the contents of this folder to your host and let everybody know about it!

Ok, but show me the code

The first lines act like a configuration area. You can change the output folder name, so that it is called superoutput, gallery, whatever you like (as long as it is a valid path name).

You may change the sizes of the generated pictures; these sizes are defined in the versions variable. Each pair means [width, height]. For example, the thumbnails are 300 pixels wide and 150 pixels high.

output_path = 'output'

versions = {
  'thumbnail' =>  [300,150],
  'big'       =>  [1024,768]
}

You can also configure which EXIF tags need to be retrieved. Since their names are too obscure for non-technical savvy people I decided to create this hash for storing the key (Exif tag) and the nice name to show with the value. So instead of showing DateTimeOriginal, it will simply output Taken.

exif_fields = {
  'Taken'     =>  'DateTimeOriginal',
  'Camera'    =>  'Model',
  'Exposure'  =>  'ExposureTime', 
  'Shutter Speed' =>  'ShutterSpeedValue'
}

There are way more tags you could show, but they can be confusing for normal people and only entertain geeks, so it's better to keep them down to a minimum.

Declare the builder object, and initialize it with the XHTML header.

x = Builder::XmlMarkup.new(:target=>xhtml, :indent=>1)

x.instruct!
x.declare! :DOCTYPE, :html, :PUBLIC, "-//W3C//DTD XHTML 1.0 Strict//EN", "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
x.html( "xmlns" => "http://www.w3.org/1999/xhtml" ) {

Now it would be amazing to have some styling in the page so that it doesn't look so ugly. We can put an style tag inside the head, and use the text! method for adding literal text to the builder object:

x.style( "type"=>"text/css" ) { x.text! "
      body{
        font-family:georgia,serif
      }
     
      h1,h2 {
        margin-top: 0;
      }
      …
      "
}

(the means there's more code but I have reduced it for clarity purposes)

Now, we need to create the output directory. I haven't bothered with outputting error messages if the directory already exists or anything. It will always try to create it:

begin
    FileUtils.mkdir output_path
  rescue
  end

We need to create a Magick::Draw object for watermarking the images, and define its parameters:

draw = Magick::Draw.new
draw.gravity = Magick::CenterGravity
draw.pointsize = 64
draw.font_family = "Helvetica"
draw.font_weight = Magick::BoldWeight
draw.stroke = 'none'
draw.fill = "#ffffff99"

Basically we are saying: use Helvetica bold 64pt, painting it with white (ffffff) and some transparency (99 for alpha channel). If you don't have Helvetica installed in your system, replace it with your favourite font.

(But since 2007 is Helvetica's 50th anniversary, you should do everything possible to use Helvetica!)

Now we open the current directory (where the script was executed) and find all files with jpg and JPG extensions, and sort them. That's because sometimes the images don't get listed in alphabetical order, and us humans like to see things in sequential order. Specially because they usually are numbered incrementally, and older numbers mean older images, so IMG001 should appear before IMG100.

Dir['*.jpg','*.JPG'].sort.each do |f|

Read each file into a Magick::Image object:

img = Magick::Image.read(f).first

And for each version…

versions.each do |k,v|

… create the version filename by appending the version name to the filename, like big_IMG_1234.jpg, and the output filename, by prepending the output path to the version filename:

version_file =  k + '_' + f
output_img_path = File.join(output_path, version_file)

If the version is 'thumbnail', we'll add the image metadata to the builder object. Note how you don't need to open or close tags, but just include things in blocks or parenthesis to get the mark up done.

if(k=='thumbnail')
        x.div('class'=>'picture') {
                x.h2(f)
                x.a('href'=> version_file.sub('thumbnail_', 'big_')) {
                        x.img('src'=>version_file)
                }
                x.dl {
                        x.dt('Dimensions')
                        x.dd(img.columns.to_s + ' x ' + img.rows.to_s)

                        exif_fields.each do |title, field|
                                key = "Exif:#{field}"
                                if img[key]!=nil
                                        x.dt(title)
                                        x.dd(img[key])
                                end
                        end
                }
        }
end

Resizing the image is as simple as

version = img.crop_resized(v[0], v[1])

crop_resized returns another Image object which we store in the version variable.

Now, if we are dealing with the 'big' version, we'll add the watermark that we prepared at the beginning. That is done with

if(k=='big')
        draw.annotate(version, 0, 0, 0, 0, "(c) soledadpenades.com")
end

You can replace my (c) soledadpenades.com with your text, of course!

And for writing the resulting image to disk:

version.write output_img_path

Very very important: do not forget to call the Garbage Collector. For some reason which I still haven't been able to elucidate, the RMagick gem leaks memory furiously. So if you forget to do a

GC.start

as I did with the first version of the script, your computer will mostly hung if you make it generate a lot of thumbnails. If you look at the current processes with top or a similar tool, you'll find a ruby process eating more and more memory with each picture it processes.

And finally, we just need to output the generated XHTML to index.html:

File.open(File.join(output_path, 'index.html'), 'w+') do |file|
  file.puts xhtml
end

Here's the result and here's the source code. With only 120 lines of code (excluding the license text :D), it's way easy to modify to suit your tastes.

Don't tell anyone but…

I must confess I got the inspiration for this from herotyc's jGallery. But he used a bash script and I thought there should be a way of doing the same with ruby :-)

20070622 Señales de que tu PHP necesita una refactorización

Dado que a bastante gente le gustó el Signs your php needs refactoring y unas cuantas personas insinuaron la necesidad de una traducción al español, he decidido actuar proactivamente y hacerlo yo misma. Y sin más dilación, sigue el artículo en castellano.

Recientemente, he tenido que trabajar con una aplicación en php que no sólo me ha dado más de un dolor de cabeza, sino que además me ha obligado a hacer uso de toda mi paciencia. Y mientras estaba en ello, pensé Esto es buen material para un artículo, de modo que nadie más haga lo mismo en el futuro, y que nadie más tenga que sufrir lo mismo que he tenido que sufrir yo.

Así que aquí están las señales de que tu PHP necesita una refactorización seria, ya mismo:

Usa variables globales

Esto tiene dos interpretaciones. En primer lugar, tenemos esa forma de programar en la que una serie de variables se pone en el ámbito global, cada función hace un

global $varA, $varB;

etc, y procede entonces a hacer lo que quiera que deba hacer con las variables. Esta es la peor; montones de errores extremadamente difíciles de trazar plagan los programas escritos con esta técnica, más que nada porque las variables globalizadas acaban sobreescribiendo variables que no deberían haber sobreescrito. Es también muy complicado poder hacer un seguimiento de quién está modificando qué, porque no se usan llamadas a funciones para acceder a las variables, sólo declaraciones global. No hay visibilidad en absoluto.

Y luego tenemos la segunda interpretación, en la que las variables que ya son globales de por sí ($_REQUEST, $_POST, $_GET) son usadas (y se abusa de ellas) a lo largo y ancho de toda la aplicación. Te puedes encontrar, por ejemplo, modelos de datos accediendo directamente los arrays $_POST o $_GET, lo cual no sólo introduce complejidad extra en su lógica (por ejemplo: ¿qué ocurre si decidimos enviar los datos con GET en lugar de con POST?) pero además también complican el hacer pruebas unitarias a los diferentes componentes de la aplicación. No puedes simplemente enviar un array de datos a un modelo: ha de ser enviado con POST o GET.

Insisto, esta forma de hacer las cosas proporciona mala visibilidad, ya que no se puede realmente distinguir quién está cambiando qué.

La fiesta de los corchetes

Cada vez que me encuentro cosas como ésta:

$variable['field']['subfield']['subsubfield1'] = 'value1';
$variable['field']['subfield']['subsubfield2'] = 'value2';
$variable['field']['subfield']['subsubfield3'] = 'value3';
$variable['field']['subfield']['subsubfield4'] = 'value4';

… sólo tengo un adjetivo en mente: asqueroso.

Es más fácil y rápido hacer algo tal que esto:

$variable['field']['subfield'] =
  array('subfield1'=>'value1', 'subfield2'=>'value2', 'subfield3'=>'value3', 'subfield4'=>'value4');

Puedes indentarlo con un par de valores por línea, al gusto. La clave está en que si en algún momento necesitas cambiar 'field' o 'subfield', no necesitas hacerlo cuatro veces (incluso si existen cosas como Buscar y Reemplazar). ¡He encontrado casos en los que la Fiesta de los Corchetes ha contaminado veinte e incluso más líneas!

Otro ejemplo de abuso de corchetes se da cuando se recuperan resultados de una base de datos en forma de arrays y son accedidos a saco. Entonces una acaba encontrándose con código como el siguiente para acceder al primer elemento:

$prop1 = $res['results'][0]['property1']
$prop2 = $res['results'][0]['property2']

Más fácil y corto:

list($prop1, $prop2) = array_shift($res['results']);

¿Me podría alguien explicar por qué esa obsesión de la gente con las Fiestas de Corchetes?

Todo es un array

Los objetos se crearon por alguna razón. El hecho de que crear arrays es muy sencillo en php y no tienes que reservar memoria primero y todo eso, al contrario que en otros lenguajes, no quiere decir que debas estructurar todos tus datos con arrays.

El problema de usar arrays como contenedores estructurados de datos es que todo lo que hay dentro es público y no hay forma de usar esas fantásticas funciones set/get que se encargan de impedir que datos incorrectos entren en el array. Por tanto, ¡usa objetos!

Esa es una razón más para pasarte a php5: puedes tener propiedades realmente privadas, de modo que nadie modificará los datos internos de tu clase, tal y como ocurre con los objetos de php4.

Código duplicado

Esto sí que me saca de quicio. Ya no sé ni cuántas veces he leído el código de una aplicación y me he encontrado las mismas tres líneas copiadas y pegadas de función en función y de fichero en fichero. Y me pregunto: ¿les habrán enseñado el concepto de función?

Si hay algo que tiene un aire remotamente familiar a algo que has hecho un poco antes, ¡lo más probable es que esté pidiendo a gritos unos toques de refactorización! Y si necesitas cierta funcionalidad en dos lugares separados, no copies y pegues el código, ¡haz una función!

No sólo el código final acaba siendo más corto, sino que además es más fácil entender cinco líneas de código, que se pueden expandir a cien cuando miras dentro de cada función, que encontrarse de golpe con cien líneas de código y tratar de entender qué está ocurriendo ahí.

El switch interminable

Hablando de bloques de cien líneas, también me he encontrado repetidamente con switch's de trescientas líneas. Y no se lo desearía ni a mi peor enemigo. ¡Es crueldad y explotación mental y debería ser perseguido criminalmente!

Obviamente, los cientos de líneas deberían ser divididos en funciones, de modo que no haga falta usar media hora en un switch para hacerse una idea de qué hace.

Tienes que modificar demasiados ficheros

Si tienes que modificar demasiados ficheros para añadir o modificar incluso la funcionalidad más simple, hay algo que no funciona en tu diseño. Esto suele ocurrir cuando las diferentes partes de la aplicación están demasiado acopladas y cada una necesita saber demasiado acerca de las demás.

Lo peor de esto es que tiende a manifestarse cuando la aplicación se hace grande y está además en modo producción-a-tope, de modo que se piden nuevas funcionalidades constantemente, y la mayoría de programadores acaba mintiéndose a sí mismos: Bueno, no pasa nada por cambiar un par de docenas de ficheros para añadir esta funcionalidad nueva, ya lo simplificaré después. Y todos sabemos perfectamente que ese después nunca llega.

Valores fijos en el código

Las constantes se crearon por alguna razón. Es malo encontrarse cosas tal que

if($result==4) {
// bla
} else if($result==5) {
// bla bla
}

donde determinados valores tienen un cierto significado, pero es aún peor encontrarse cosas como

if($result=='row1') {
// bla
} else if($result=='row2') {
// bla bla
}

ya que por ejemplo, si tecleas algo mal y en lugar de row1 escribes rowl, PHP no se quejará porque es una comparación perfectamente válida. Lo que tú necesitas es usar constantes, de modo que cada vez que intentes usar una constante que no ha sido definida, PHP se queje y tú lo arregles inmediatamente.

Además, aunque parece sencillo distinguir entre "1" (el número uno) y "l" (L minúscula), no es tan sencillo para personas con problemas como dislexia, o simplemente, tú mismo, cuando estés cansado. Y los errores introducidos por culpa de no usar constantes son terriblemente difíciles de localizar; la mayoría de ocasiones hay que pasarse horas yendo línea por línea y tratando de averiguar por qué no funciona. Es mucho más fácil y preventivo definir constantes y dejar de preocuparse de tener que actualizar todos los valores puestos a mano en el código si hace falta cambiarlos luego.

Inconsistencias en la interfaz

Es algo de lo que no se suele hablar mucho, pero creo que es realmente preocupante en PHP. No estoy segura de si es algo inducido por el lenguaje en sí (no hay más que echar un vistazo a las funciones de cadenas), pero hay una extraña tendencia en las aplicaciones php que las lleva a no seguir convención alguna en lo que respecta a argumentos de funciones y tipos de valores devueltos.

A veces las funciones devuelven valores booleanos (true o false) o valores que pueden hacer de booleanos (0 ó 1), otras veces usan valores de retorno al estilo C (0 para éxito y 1 o más para los errores), que son obviamente lo contrario a usar el booleano true para éxito y el booleano false para error, ya que en PHPlandia 0==false y 1==true (a menos que uses los operadores === y !==, más estrictos, pero desafortunadamente ese no es el caso de la mayoría de desarrolladores en php)

En otros casos, las funciones no devuelven nada, pero en cambio usan un array pasado por referencia para escribir resultados en él, algo tal que esto:

function my_function(&$return_array)

Esta práctica es algo que realmente me desagrada, porque a menos que acabes de ver la definición de my_function, es imposible distinguir si

my_function($my_array)

está usando $my_array como un parámetro de entrada o de salida.

Es mejor ponerse de acuerdo en un estilo para devolver valores, y usar ese estilo consistentemente en todas las funciones que escribas. Tal que: siempre devolveremos un objeto con dos propiedades, error que es booleano y representa si la función falló o no, más results que contendrá datos si necesitamos devolver algo.

Con eso, sabes que siempre puedes verificar el valor de $res->error en lugar de tener que verificar primero si existe o no, y entonces ver el valor en sí.

Ya captas la idea…

(Nota: en los comentarios de la versión en inglés se recomienda usar excepciones en lugar de esta solución. Lamentablemente, es sólo aplicable si usas php5)

Conclusión

Algunos de estos problemas prácticamente desaparecerían si tuviéramos un editor de php verdaderamente bueno. Aunque Eclipse cumple su labor decentemente con los plugins para php, la mayor parte del tiempo y debido a la forma en que php funciona, todo queda patas arriba y la funcionalidad de autocompletado es absolutamente inútil porque Eclipse no puede encontrar las clases. Refactorizar es algo que casi depende sólo de tu memoria a corto plazo (creo que ví algo parecido a esto en algún sitio…); otros problemas dependen de si la gente programa estando drogada (recordemos el switch de 300 líneas) o de la competencia en PHP y diseño de software en general.

¡Y ahora es el momento de volver a tu aplicación y mirarla con ojos críticos!

20070605 Signs your PHP needs refactoring

I have had to go through a php application recently which has given me more than one headache and has required me to use all my possible patience. While working with it, I thought This is good material for an article, so that nobody else does the same in the future, and nodody else will need to experience the same displeasure as I have had to.

So here are the signs your PHP application needs a serious refactoring, right now:

Uses global variables

This one has two readings. In the first one, there's that coding style in which a series of variables is placed in the global scope, each function simply does

global $varA, $varB;

etc, and proceeds to do whatever it needs to do with the variables. This one is the worst one; lots of very hard to trace errors plague programs written with this technique, most often because globalized variables end up overwriting variables which they shouldn't, so that's bad. It's also very complicated to keep track of who's modifying what, because there aren't function calls to access the variables, only global statements. There is no visibility at all.

Then there's the second reading, in which readily available global variables ($_REQUEST, $_POST, $_GET) are again used (and abused) throughout the whole application. You can find, for example, data models accessing directly the $_POST or $_GET arrays, which not only introduces extra complexity into their logic (what if we decide to send data with GET instead of POST?, for example) but also complicate unit testing the different pieces of the application. You can't just send an array of data to a model - it has to be in POST or GET.

Again, this way of doing things offers bad visibility, since you can't really tell who's changing what.

Brackets galore

Whenever I find things like this:

$variable['field']['subfield']['subsubfield1'] = 'value1';
$variable['field']['subfield']['subsubfield2'] = 'value2';
$variable['field']['subfield']['subsubfield3'] = 'value3';
$variable['field']['subfield']['subsubfield4'] = 'value4';

… a word comes to my mind: disgusting.

It is way easier and faster to just do something like this:

$variable['field']['subfield'] =
  array('subfield1'=>'value1', 'subfield2'=>'value2', 'subfield3'=>'value3', 'subfield4'=>'value4');

You can indent it having one pair of array values per line, as you wish. The point is that if you ever need to change 'field' or 'subfield', you don't need to do it four times (even if there are things like Search and Replace). I have found cases where the Brackets Galore had contaminated twenty and sometimes even more lines!

Another example of brackets abuse happens when people retrieve results from databases in the form of arrays and access them in the wild. And you end up finding code like this one for accessing the first element:

$prop1 = $res['results'][0]['property1']
$prop2 = $res['results'][0]['property2']

Easier and shorter way:

list($prop1, $prop2) = array_shift($res['results']);

Could somebody explain me what's that obsession of people with Brackets Galores?

Everything's an array

Objects were created for some reason. The fact that creating arrays is very easy with php and you don't have to allocate memory first and all that unlike other languages doesn't mean that you have to structure all your data with arrays.

The problem with using arrays as structured data containers is that everything inside them is public and there's no way of having nice set/get functions which prevent bad data to enter the array. So, use objects!

That is yet another reason for moving to php5: you can have really private properties, so that nobody will modify internal data as it can happen with php4's objects.

Duplicated code

This one really gets on my nerves. How many times have I looked at an application, just to find the same three lines being copied and pasted from function to function and from file to file? And then I wonder: have they ever been taught the concept of function?

If there's something there which looks vaguely similar to something else you did a bit before, it is probably asking for some factorization love! And if you need certain functionality in two separate places, do not copy and paste the same code, make it a function!

Not only the final code ends being shorter, but it is easier to understand five lines of code which can expand to one hundred when you go inside each function, than to get shown one hundred lines of code all of a sudden and try to find out what is going on there.

The neverending switch

Talking about one-hundred-lines blocks, I have also recurrently found three hundred lines switch statements. And believe me, I wouldn't recommend it to my worst enemy. This is cruelty and mental exploitation at its worst and should be criminally punished!

Obviously, the hundreds of lines should be split into functions, so that you don't need to spend half an hour reading a switch to get an idea of what does it do.

You have to modify too many files

If you need to modify lots of files for adding or modifying even a simple feature, something is not working in your design. It usually happens when the different areas in the application are excessively coupled and each one needs to know too much about the other.

The main problem with this is that it tends to manifest itself when the application is getting larger and is also in big production mode, so new features are highly demanded and most of the developers just lie to themselves: It's OK to have to change a few dozen files for adding this new feature, I'll work on simplifying this later. And you know that later never happens.

Hard coded values

Constants were defined for some reason. It is bad to find things like

if($result==4) {
// blah
} else if($result==5) {
// blah blah
}

where numeric values are supposedly meaning something, but it is also quite bad to find things like

if($result=='row1') {
// blah
} else if($result=='row2') {
// blah blah
}

because if for example, you misspell something and instead of row1 you write rowl, PHP is not going to complain at you since it's a perfectly valid comparison. What you need is to use constants, so that whenever you try to use a constant which hasn't been defined, PHP complains and you fix it immediately.

While it looks fairly easy to distinguish between "1" (the number one) and "l" (the lowercase L), it is not that easy for people with problems like dyslexia, or put it simply, when you're tired. And the errors introduced because of not using constants are extremely hard to trace, most of the times you have to spend insane amounts of time going line by line of code and trying to find out why it doesn't work. It's just easier and more preventive to define constants and stop worrying about having to update all the hard coded values in the code later on if needed.

Interface inconsistency

This one doesn't seem to get much attention but it is a really worrying area in PHP. Not sure if it's something inducted by the language itself (just have a look at the string handling functions), but there's an strange tendency in php applications to not to follow standards in what regards to function arguments and return types.

Sometimes functions return boolean values (true or false) or boolean like values (0 or 1), other times they use C style return types (0 for success and 1 or more for errors), which are clearly opposite to using boolean true for success and boolean false for error, since in PHP land 0==false and 1==true (unless you use the stricter === and !== operators, which unfortunately seems to not to be the case for most of the php developers around)

In some other cases, functions do not return anything, but instead use an array passed by reference to write results in it, looking somehow like this:

function my_function(&$return_array)

. I really dislike this practice, because unless you just saw the function definition for my_function, it's impossible to distinguish if

my_function($my_array)

is using $my_array as an input or output parameter.

It is better to agree on a style for return values, and use that style consistently in every function you write. Like: we'll always return an object with two properties, error which is a boolean and represents whether the call failed or not, plus results which will contain data if we need to return something.

With that, you know that you can always check the value of $res->error instead of having to check first if it exists or not, and then check the value itself. You get the idea…

Conclusion

Some of these issues would almost disappear if we had a really good php editor. While Eclipse does a decent job with the php plugins, most of the time, because of the way that php works, everything gets messed up and the autocomplete feature it's useless because it can't find the classes. Refactoring is something that almost relies on your short-term memory only (I think I saw something like this somewhere…), and other issues depend on people being high or not when programming (remember the 300 lines switch) or being competent in PHP and software design in general.

And now is the time to go back to your application and look at it with critical eyes!

20070122 PHP will never have a (real) Rails-like framework

I know the title is harsh but it's so true. At least it is according to nowadays php's implementation of classes and objects, which do not permit to "reopen" and add or redefine new methods to an existing class definition, which is the basis upon Rails (and I presume lots more of applications and frameworks) is built.

This ruby feature managed to freak me out when I first read about it. Redefining an existing class? Who would think of it as a good idea? Where is the maintainability and the good practices of object oriented programming? How can we rely on some class behaving as expected if some piece of code is changing its internal behaviour?

But then I got the answer - when used within reason, this allows you to extend existing classes. Extend. Morph. Adapt. Improve. Refine. Lots of concepts which started jumping around me and made me understand all in a sudden how Rails plugins worked so seamlessly, without having to do any extra include, or without having to touch Rails very core files, or defining hooks at certain places. If you don't like some aspect of Active Record, you could write a plugin which overwrites that behaviour - only that one. The rest remains the same.

The aesthetics is somehow shocking for php-only programmers. It's something like this:

class A
function hello_world
puts "I'm hello_world"
end

Any instance of A running hello_world will output "I'm hello_world"

But if you add this anywhere after the definition of A

class A
function hello_world
puts "I'm hello_world v2"
end

and run hello_world again, you will get "I'm hello_world v2". Which definitely is impossible to do in PHP - you would get a Fatal error: Cannot redeclare class error as soon as you tried to "reopen" a class and add or redefine some methods.

While this is not a problem for the average use of php, it turns to be the opposite when you want to do something smart with php5's new and shiny objects model. Something like, for example, building a cool framework like Rails.

There have been some attempts already, like for example CakePHP or Symfony. I just have experience with CakePHP and while it is magnifically built (given that it maintains compatibility with php4 and php5) it will never reach the whole expressivity and power that Rails has.

A quick example is the AppModel class. AppModel is the CakePHP's equivalent of ActiveRecord::base. In Rails, when you declare a model you just extend ActiveRecord. Simple as that; you don't need extra stuff in the middle. In CakePHP you need to extend AppModel, and if you want to modify AppModel in your application, you have to write a new AppModel.php - which cake will load instead of the default, empty one. Yes, AppModel is an empty class whose sole purpose is extending Model (which has the real ActiveRecord-like methods). That doesn't sound very flexible.

So at the end, AppModel is not more than a simple intermediate step for overcoming the limitation of php's inability to redefine the underlying class, that is, Model. We need to add an extra class in the middle for each level that you anticipate the user of your classes will want to redefine or extend.

Meanwhile, in Rails you would just add some code in the plugins directory with the new functions for ActiveRecord, and your models would still extend ActiveRecord::base. No extra levels of hierarchy whatsoever.

Another interesting example is the famous acts_as_taggable plugin, which allows programmers to add the ability to tag items (i.e. ActiveRecord models) just by adding a single line of code to the model (acts_as_taggable), using ruby's ability to reopen classes and add a series of new methods to existing models.

Even more, there are some Ruby core classes, like Date, to which Rails adds new methods, while they still belong to the Date object, not an artificial AppDate intermediate object in the middle, and without modifying Ruby's core files. Isn't it beatiful?

And before you discard my arguments as biased towards Rails, there are more languages which allow for classes to be reopened, like Javascript (and I believe ActionScript was like that before, don't know about ActionScript 3). These flexible languages have allowed people to write such amazing stuff as Prototype or Script.aculo.us, by making use of the redefinition and extension of existing classes.

So that's why I say that PHP is not flexible and will never have a real Rails-like framework :-)

Hope it's clearer now…

20061129 Some things I've learnt about managing developers teams

During the past three years I've been working in two different environments: big and small companies. Both producing the same kind of final products (corporate applications with web interfaces) have similar problems, and I thought it may be interesting to share them with you so we can find out if there's any solution, and if not, we always can complain and moan about the horrible career we have chosen for our life and how well we would do taking care of green lettuces in a peaceful but lost country farm. So there we go with my appreciations!

About Open Source

  • Open Source is good but it is not free
    Although having access to the source code of something means you can adapt the software at your complete will, it doesn't imply that it will be quicker than writing it from scratch. The Open-* Philosophy is great, brilliant, but contributors come from very different backgrounds and sometimes the quality is not what you would expect. Most of the times, mixing several open source projects under another one results in a funky mix of interfaces, classes and methods, with lots of conversions and patches here and there. That is not good, mainly if you want a robust, well thought code, and also for obvious maintenance reasons.
  • Using OS without contributing back to the community sucks
    You might believe you're ingenious by using Open Source code and saving some money, thus gaining advantage over your competitors, but developers feel bad about doing that. They know they should give something back to the community and feel really dispaired when you strictly forbid it "because it would mean losing your investment".

About the skills

  • The cheapest option is always the most expensive
    Hiring unexperienced developers at a very cheap salary with the hope that they will come up to date in a couple of months is an utopia. The senior developers will feel stupid having to explain once and once again the basics to someone who must know that, and then will get unmotivated the third time they have to argue why using functions instead of copying and pasting the same code is better, for example.
  • Sometimes, employees know more than the employer
    Face it. You may have lots of experience from ten years ago, you may know how to negociate even with a Demon, but you're not up to date with nowadays technologies.
    If they discuss any of your decissions, do not try to impose your methods using brute force. It is not an act of rebellion which needs to be dealt with quickly. Just listen to them and learn the most that you can, then think again about your decission.
  • Improving the skills
    Good developers are curious, they love to learn new things. Allowing, and encouraging them to spend work time to find out new techniques and be up to date will not only make them happy and unestressed but that will also reflect in the efficiency of your products.
  • Respect the spare time
    Everybody needs to rest and have a break from work, even if you think that it is superexciting. Making the people stay for half an hour more every day, suggesting to study new things in their commute home, etc, it's not only dishonest but it's also stressing.

About the interface

  • You absolutely need a designer
    Every interface should be created by a designer. They know where to place things. They are professionals on that. No matter how distinguished and exquisite your graphical skills are, you will never be as good as a real designer.
    If you can't afford to hire a designer full time, just look for any decent agency and get a good design made for your product. (I could spend hours describing the horrible interfaces I've seen in these three years, all of them consequence of wanting to save some money in the designer area.)
  • Good print designers may be horrible web designers
    Basically, what works in paper may not work in a screen. The style guide of a corporation may be appropiate for printed materials but not for a web product. Unfortunately, there are lots of self-called web designers which create painful html+css layouts, impossible to understand, maintain or modify, so finding a really good web designer may be a tedious task, but will prove to be worth it.
  • An interface design is more than a screenshot
    Good interface design will be based on a style guide. Do not think of an style guide as an arbitrary imposition of rules, think of it as a framework that will help you develop the application, saving time on decissions and not having to fix things which are not consistent later on. It is better to provide the developers with all the elements that they will need for the development: logotypes in the needed sizes, interface elements (bullets, fonts), colours (do not give them a Pantone number, they are not designers and they do not have a Pantone list: give them an HTML hexadecimal code, as that's what they will finally use).
    By doing so, it's very complicated that they miss anything.

About treating people

  • Developers aren't machines for converting code into money
    They are people, and they have feelings, and they also notice yours. If you're trying to manipulate them, they will notice. And they will turn angry at that (possibly leaving the company in the most stressful moment).
  • Don't try to look smarter than you really are
    Because good programmers are also good observers, they will notice instantly that you're pretending to be what you're not, and will probably lose respect for you.
  • Verbosity produces boredom
    Being detailed is good. Developers love to hear details about things because it helps them to anticipate what's next, getting a better overview of everything, which is a must for doing a good product. But being too verbose each time you get to talk to them will make them avoid talking to you, because you'll bore them, and they hate boredom. You don't need to revisit every single detail when you're being asked a simple question, nor is there need for explaining the technical implications of using one or another method for whatever to someone which possibly already told you about those technical implications (because he noticed before). Keep it short and they will come back often!
  • Keep meetings to a minimum
    Directly related to the above suggestion!

About your clients

  • Your client might use IE, but the public might not
    Your client's browser is not the browser that people will use. Do not develop for their browser. Develop for the standards, and you won't get angry calls some years after when (hopefully) bad hacks for IE stop working.
    Also, developers tend to use Firefox. Telling them to use IE "because that's what the client uses" will turn them into an anger machine, and you don't want that, obviously.
  • Your client might be wrong
    He doesn't neccessarily need that flash intro, for example.

About the users

  • Users are not idiots
    It may occur that the interface is confusing them and then they act as idiots. Maybe they have a different logic - not everybody thinks like you. Maybe you didn't test properly in other scenarios and they are getting errors that didn't arise in your environments.
    But if you refer to them as idiots, the developers will finally believe it, and get unmotivated, because no one likes to work for idiots.

Can't really think of something else now. Feel free to add whatever you are missing in the comments!