Cómo encontrar un programador que sepa programar.
2010-03-11 15:09:58Si todavía no leíste Why Can't Programmers.. Program? de Jeff Atwood andá, leélo y volvé.
¿Ya te asustaste? No lo hagas, el problema es el proceso de contratación.
Sí, hay montones de personas que se presentan para trabajos de programador y no saben programar. Eso es normal.
Está relacionado con una cosa que escribió Joel Spolsky (extrañamente, socio de Atwood en stackoverflow.com).
Suponéte que querés contratar a alguien en el top 1% de los programadores.
Tenés 100 postulantes, de ellos 99 no pueden programar. 1 puede, y lo contratás.
Después la empresa de al lado necesita lo mismo. Tienen 100 postulantes, 99 no pueden programar... ¡y 80 son los mismos que la otra compañía rechazó!
Así que no, contratar al mejor de 100 no es la manera de tener un programador "top 1%", es simplemente tu intuición estadística que te hace equivocar.
No querés contratar a alguien en el top 1% de los postulantes, querés uno en el top 1% de programadores. Diferentes universos.
Estas dos cosas son los dos lados de la misma moneda. 99% de los postulantes son inútiles, por eso son postulantes, porque no pueden conseguir trabajo y no tienen trabajo porque son inútiles como programadores.
Juzgar a los programadores por el standard de los postulantes que se presentan es como juzgar la calidad de un restaurante lamiendo su tacho de basura.
Ahora, habiendo entendido esto, ¿cómo se encuentra un programador que pueda programar?
¡Fácil! ¡Buscás uno que tenga programas para mostrarte!
Nunca contrataría a un programador que no me pueda mostrar código. Tiene que tener un problema porque los programadores programan.
Es lo que hacemos. ¿Si no lo hacemos que somos? ¿Teóricos?
Veamos algunas objeciones obvias:
Programó para su trabajo anterior y no lo puede mostrar.
Ok, lohizo. ¿Qué más escribió? ¿Algo open source? ¿fragmentos en un blog? ¿Respuestas en stackoverflow?
¿Nada? ¿No escribió nada sin cobrar? No es el que quiero. Si sólo programa por dinero no tiene pasión por la programación, o no lo disfruta. Probablemente no es muy bueno tampoco.
Está terminando la universidad, todavía no escribió mucho.
¿Porqué? ¿Qué está esperando? ¿Qué lo detiene? Lleva años estudiando como programar! ¿Qué hizo con el conocimiento que fué adquiriendo? ¿Lo guarda para cuando cumpla 25? ¿No practicó su arte? No es el programador que buscamos.
Pero conseguir alguien que te muestre código no es suficiente por supuesto. También tiene que ser buen código, si estás seriamente tratando de contratar programadores excelentes.
Así que aquí hay unos criterios extra:
- Fijáte en qué lenguakes programa. Si programa COBOL por gusto puede o no ser lo que necesitás.
- Open source == bonus points: quiere decir que no lo avergüenza su código, y hace que sus credenciales sean triviales de verificar.
- Si es el líder de un proyecto con múltiples colaboradores y lo hace bien, está a mitad de camino de ser un programador/manager, muchos bonus points!
- Proyectos con un historial de commits largo muestran responsabilidad y criterio.
- Listas de correo de desarrollo te permiten estimar su personalidad. ¿Es irritante? ¿Es sensible? ¿Es molesto?
Y después está lo obvio, referencias, entrevistas, ejercicios, pero esos son filtros secundarios, lo importante es que pueda programar, y mostrarte su código es la forma de hacerlo.
Un par de horitas hackeando Kuatia...
2010-03-03 19:28:21Como he comentado hace un tiempito, de a ratos ando tratando de hacer un procesador de texto tipo "prueba de concepto". Por ahora está hsoteado en googlecode y se llama kuatia.
Obviamente no está ni cerca de ser útil para algo, pero... puede hacer listas itemizadas o numeradas anidadas.
Acá hay una captura del editor y de la salida PDF que produce vía reStructured Text:

No me parece que esté tan mal.
Marave 0.7 liberado
2010-02-25 11:16:12Acabo de subir la versión 0.7 de Marave mi editor de pantalla completa a http://marave.googlecode.com
Marave es un editor "relajado" inspirado por ommwriter, DarkRoom y muchos otro. Posee una interfaz espartana a pantalla completa con elementos que se "desvanecen" para no interponerse entre el usuario y su texto.
Soporta resaltado de sintaxis, corrector ortográfico en línea, música de fondo, feedback audible de teclado, temas, extensión via plugins, y mucho más.
La captura de pantalla obligatoria:

No hay grandes features nuevos en 0.7 pero hay cambios internos grandes, y bugs importantes corregidos:
- Corregido bug que rompía abrir archivos si no había corrector ortográfico
- Implementado soporte para lenguajes RTL
- Varios arreglos menores
- Refactoreado completo del componente editor
Un adelanto de una idea
2010-02-24 14:13:30Vengo pensando en qué es lo que realmente pero realmente necesito en un procesador de textos. Y en qué se necesitaría para crear una cosa así.
Unos minutos jugando me han llevado por el camino de este adelanto (video acá por si no lo ven <):
¿Se convertirá en algo? ¡Quién sabe!
Editor: un QTextEdit mejor
2010-02-23 14:23:06Escribir un editor de texto es reinventar la rueda. Ya lo sé. Me digo a mí mismo Marave es una linda rueda, con características propias, y creo que eso es cierto, pero, si estás reinventando la rueda, no sirve de nada reinventar el eje y el rayo también.
Por eso refactoreé todas esas cosas que yo creo que un editor de texto debe tener en una linda biblioteca, para que la próxima vez que alguien deba reinventar la rueda, pueda usar los bonitos rayos y eje de Marave.
Entonces, aquí está Editor, la clase con el nombre más obvio posible! Es un widget de edición de texto para PyQt con features extra, que se puede usar como reemplazo de QTextEdit o QPlainTextEdit.
Por ahora, vive adentro del SVN de Marave pero tal vez algún día salga de ahí.
Éstos son los features:
Resaltado de sintaxis:
Y no "en teoría", como QTextEdit y demás! Editor puede resaltar un montón de lenguajes porque usa GNU source highlight via el Source Highlight Qt de Loreno Bettini.
Corrector ortográfico
Si instalás PyEnchant con los diccionarios correctos, hace corrección ortográfica online.
Widgets de Buscar y Buscar y Reemplazar
La clase Editor te da lindos widgets para buscar y buscar y reemplazar ya conectados con el widget del editor, para que lo agregues fácilmente a tu aplicación.
Métodos new/open/save/saveas:
No implementes abrir/guardar, etc! Eso es siempre el mismo código!
Ojalá le sirva a alguien más :-)
Capítulo adelanto de "Grok 1.0 Web Development"
2010-02-23 12:03:28La gente en Packt Publishing me mandó una copia de Grok 1.0 Web Development por Carlos de la Guardia para que la comente.
Lo estoy leyendo, y voy a escribir algo en unos días (De paso: está bueno! Propongo este slogan para Grok: Como Zope, pero sin el Java [1]), y acá hay un capítulo de muestra para que vean de qué se trata. Es fácil de leer sin el resto del libro:
Esta semana estuve peleando con ese engendro que eran los Django oldforms (sitio viejo, ni pregunten), así que los forms de Grok me parecieron encantadores! ;-)
[1] Sí, por supuesto que Zope no tiene Java, sólo se siente como si fuera Java ;-)
¿Tenemos tan poca idea de lo que cuesta el software?
2010-02-22 00:54:03Esto dice Ohloh del costo de desarrollar Marave:

Realmente, Marave es como mucho un mes de programar part-time. Cómo puede eso humanamente ser U$S71355 o "1 año persona"?
¿Esta basura es lo mejor que tenemos para estimar costos? Si es así, la próxima vez que vean algo como "El programa X llevaría Y años y costaría Z dólares", recórtenlo por un factor de 10 o más.
Ésto es lo que costó desarrollar Marave:
- Nada
Bueno, ésto es lo que hubiera costado si lo cobrara:
Estoy suponiendo unas 100 horas de mi tiempo. A mi precio de "ojalá me lo paguen", U$S 40/hora, son U$S 4000, que quiere decir que Ohloh le pifia por un 1600%.
Por otro lado, por tanto trabajo freelance no te voy a cobrar precio completo, lo más seguro es que te cobra algo como U$S 20/hora lo que quiere decir que Ohloh está un 3000% arriba.
En conclusión: si te gusta mi código (y lo podés ver por vos mismo), contratame, soy o increíblemente barato o increíblemente rápido.
Marave 0.6 en la calle
2010-02-21 21:49:36La versión 0.6 de Marave, mi tranquilo editor a pantalla completa está en el lugar de siempre: http://marave.googlecode.com
Cosas nuevas:
- Resaltado de sintaxis
- Plugins
- Bugs arreglados
- Animaciones más bonitas
- Limpieza de código
Captura de pantalla gratuita:
El momento ajá!
2010-02-19 22:07:00Hoy quise hacer una cosita en Marave. El objetivo era:
- Hacer un "fade in" de un widget
- Setear una variable
- Hacer un "fade in" de otro widget
Es importante hacerlo en ese orden y es importante que la aplicación siga respondiendo.
Acá está el código que usé (simplificado):
def fadein(thing, target=1., thendo=None): """ * thing is a QWidget * thing.proxy is a QGraphicsWidget * thendo is callable * target is the desired opacity """ thing.anim=QtCore.QPropertyAnimation(thing.proxy, "opacity") thing.anim.setDuration(200) thing.anim.setStartValue(thing.proxy.opacity()) thing.anim.setEndValue(target) thing.anim.start() thing.anim.finished.connect(thing.anim.deleteLater) if thendo: thing.anim.finished.connect(thendo)
Y se usa así:
def later(): avar=avalue fadein(widget2) fadein(widget1, thendo=later)
¿No es lindo? Tener funciones como objetos de primera clase significa que puedo tomar later como un closure, junto con widget2 y avar que sólo necesitan estar definidas en el scope local, y la cadena de llamadas funciona ¡exactamente como quiero!
Sí, en muchos otros lenguajes se hace lo mismo, y en Javascript es un truco común... ¡pero PyQt es un wrapper de C++!
Me parece que este tipo de uso muestra el valor agregado que PyQt te da, no es solamente que con python evitás la compilación aburrida, o que tenés la increíble biblioteca estándar, sino que el lenguaje mismo te deja hacer cosas que no son prácticas en C++.
La única manera que se me ocurre de hacer esto en C++ es crear un slot que sea el equivalente de later, y encadenarlo a la señal... lo que quiere decir que ese later descartable se convierte en parte de la interface de la clase. (!?)
Habría que definir later en algún otro lado del archivo, separado de su único uso (tal vez inine en el header).
Aún así, eso no es equivalente: avalue podría ser algo no fácil de acceder cuando se ejecuta later (por ejemplo, el timestamp del primer fadein), habría que buscar donde guardarlo para que later lo encuentre, no se puede volver a hacer esto hasta después que se ejecute later... se pone complicado.
A veces programar es como una cachetada... te das cuenta que cosas que usás sin pensar no son nada triviales.
Así que recuerda joven aprendiz: podés elegir las herramientas. Elegí con cuidado.
Extendiendo Marave
2010-02-18 18:50:20Marave es un editor de texto. Si hay una cosa que es cierta de todos los editores es ésta: siempre les falta un feature que necesitás.
Entonces la solución, en la antigua tradición de Emacs y Vim es... hacerlo extensible.
Soy un gran fan de los programas extensibles por el usuario.
Así que... acá está la anatomía de un plugin de Marave tal como funciona ahora mismo en SVN trunk, lo que por supuesto puede cambiar en cualquier momento.
Creando un plugin
Sólo hay que crear un archivo .py en la carpeta plugins. Éste es el plugin más básico, que no hace nada:
# -*- coding: utf-8 -*- from plugins import Plugin class Smarty(Plugin): name='smarty' shortcut='Ctrl+.' description='Smart quote and dash replacement' mode="qBde"
Valores por default de algo configurable (en este caso "mode") se ponen en la clase.
Los campos obligatorios:
- shortcut: un atajo de teclado que dispara este plugin
- name: un nombre corto
- description: una descripción de una línea
¿Qué hace esto? Agrega el plugin a la lista en el diálogo de preferencias, y se puede abrir el diálogo de configuración del plugin, donde se puede cambiar el shortcut:

Si se habilita este plugin, cuando el usuario use ese shortcut, se llama al método "run" del plugin.
Haciéndolo Configurable
Éste plugin soporta distintos modos de operación. Para hacer que esto sea accesible al usuario, hay que implementar unos pocos métodos mas.
El método addConfigWidgets toma como argumento un diálogo, y agrega lo que uno quiera ahí:
@classmethod def addConfigWidgets(self, dialog): print 'Adding widgets to smarty config' l=dialog.ui.layout self.q=QtGui.QCheckBox(dialog.tr('Replace normal quotes')) if 'q' in self.mode: self.q.setChecked(True) self.b=QtGui.QCheckBox(dialog.tr('Replace backtick-style quotes (` and ``)')) if 'B' in self.mode: self.b.setChecked(True) self.d=QtGui.QCheckBox(dialog.tr('Replace -- by en-dash, --- by em-dash')) if 'd' in self.mode: self.d.setChecked(True) self.e=QtGui.QCheckBox(dialog.tr('Replace ellipses')) if 'e' in self.mode: self.e.setChecked(True) l.addWidget(self.q) l.addWidget(self.b) l.addWidget(self.d) l.addWidget(self.e)
Y entonces el diálogo de configuración se ve así:

También queremos que esas opciones se puedan guardar en algún lado, entonces reimplementamos saveConfig:
@classmethod def saveConfig(self, dialog): self.shortcut=unicode(dialog.ui.shortcut.text()) self.settings.setValue('plugin-'+self.name+'-shortcut', self.shortcut) newmode="" if self.q.isChecked(): newmode+='q' if self.b.isChecked(): newmode+='B' if self.d.isChecked(): newmode+='d' if self.e.isChecked(): newmode+='e' self.mode=newmode self.settings.setValue('plugin-smarty-mode',self.mode) self.settings.sync()
Y queremos que esas opciones se lean antes de crear el plugin, entonces:
@classmethod def loadConfig(self): print 'SMARTY loadconfig', self.settings if self.settings: sc=self.settings.value('plugin-'+self.name+'-shortcut') if sc.isValid(): self.shortcut=unicode(sc.toString()) mode=self.settings.value('plugin-smarty-mode') if mode.isValid(): self.mode=unicode(mode.toString())
Que haga algo!
Y sí, hay que hacer que sirva para algo. El plugin tiene acceso a un "client" que es la ventana principal de Marave. Todo está ahí, en alguna parte ;-)
def run(self): print 'running smarty plugin' text=unicode(self.client.editor.toPlainText()).splitlines() prog=QtGui.QProgressDialog(self.client.tr("Applying smarty"), self.client.tr("Cancel"), 0,len(text), self.client) prog.show() output=[] for i,l in enumerate(text): output.append(unescape(smartyPants(l,self.mode))) prog.setValue(i) QtGui.QApplication.instance().processEvents() prog.hide() self.client.editor.setPlainText('\n'.join(output))
Y ya está, si se habilita el plugin smarty, se pueden "arreglar" las comillas, guiones y elipsis con una combinación de teclas :-)
Código fuente completo aquí: http://code.google.com/p/marave/source/browse/trunk/marave/plugins/smarty.py
Falta hacer: otras maneras de integrar plugins en la interface, botones, paneles, etc.

