como ser un buen programador

Recurso tomado del ensayo original How To Be A Programmer: A Short, Comprehensive and Personal Summary (PDF) y traducido por Copyright © 2002, 2003 Robert L. Read

Tabla de Contenido

1. Introducción
 
2. Principiante
Habilidades Personales
Aprende a Depurar
Cómo Depurar Dividiendo el Espacio del Problema
Cómo eliminar un Error
Cómo Depurar Usando una Bitácora
Cómo Comprender Problemas de Desempeño
Cómo Corregir Problemas de Desempeño
Cómo Optimizar Ciclos
Cómo Lidiar con el Costo de E/S
Cómo Administrar la Memoria
Cómo Lidiar con Bugs Intermitentes
Cómo Aprender Habilidades de Diseño
Cómo Conducir Experimentos
Habilidades de Equipo
Por Qué la Estimación es Importante
Cómo Estimar el Tiempo de Programación
Cómo Encontrar Información
Cómo Utilizar a la Gente como Fuentes de Información
Cómo Documentar Sabiamente
Cómo Trabajar con Código Pobre
Cómo Usar el Control del Código Fuente
Cómo Probar Unidades
Toma Descansos Cuando estés Confundido
Cómo Reconocer Cuándo Ir a Casa
Cómo Lidiar con Gente Difícil
3. Intermedio
Habilidades Personales
Cómo Permanecer Motivado
Cómo ser Ampliamente Confiable
Cómo Negociar Tiempo vs. Espacio
Cómo Hacer Pruebas de Estrés
Cómo Balancear Brevedad y Abstracción
Cómo Aprender Nuevas Habilidades
Aprende a Teclear
Cómo Hacer Pruebas de Integración
Lenguajes de Comunicación
Herramientas Pesadas
Cómo Analizar Datos
Habilidades de Equipo
Cómo Administrar el Tiempo de Desarrollo
Cómo Manejar Riesgos de Software de Terceras Partes
Cómo Manejar Consultores
Cómo Comunicar la Cantidad Adecuada
Cómo Disentir Honestamente y Sobrellevarlo
Juicio
Cómo Negociar Calidad Frente a Tiempo de Desarrollo
Cómo Manejar la Dependencia del Sistema de Software
Cómo Decidir si el Software es Muy Inmaduro
Cómo Hacer una Decisión de Compra vs. Construcción
Cómo Crecer Profesionalmente
Cómo Evaluar Entrevistados
Cómo Saber Cuándo Aplicar Ciencia Computacional Fantasiosa
Cómo Hablar con No Ingenieros
4. Avanzado
Juicio Tecnológico
Cómo Diferenciar lo Difícil de lo Imposible
Cómo Utilizar Lenguajes Embebidos
Escogiendo Lenguajes
Comprometiéndote Sabiamente
Cómo Combatir Presión de Calendario
Cómo Comprender al Usuario
Cómo Obtener una Promoción
Sirviendo a Tu Equipo
Cómo Desarrollar Talento
Cómo Elegir Sobre Qué Trabajar
Cómo Obtener lo Máximo de Tus Compañeros de Equipo
Cómo Dividir Problemas
Cómo Manejar las Tareas Aburridas
Cómo Conseguir Apoyo para un Proyecto
Cómo Hacer Crecer un Sistema
Cómo Comunicar Bien
Cómo Decirle a la Gente Cosas que No Desean Escuchar
Cómo Lidiar con Mitos Administrativos
Cómo Lidiar con el Caos Organizacional
 
 

Capítulo 1. Introducción

 

Ser un buen programador es difícil y noble. La parte
más difícil de hacer real una visión colectiva de un proyecto de
software es lidiar con los compañeros de trabajo y con los clientes de
uno. Escribir programas de computadora es importante y requiere gran
inteligencia y habilidad. Pero realmente es un juego de niños
comparado con todo lo demás que un buen programador debe hacer para
lograr que un sistema de software tenga éxito tanto para el cliente
como para la miríada de colegas por quienes se es parcialmente
responsable.

Esto es muy subjetivo y, por lo tanto, este ensayo
está condenado a ser personal y algo testarudo. Me confino a mí mismo a
los problemas que un programador muy probablemente tiene que
enfrentar en su trabajo. Muchos de esos problemas y sus soluciones son
tan generales a la condición humana que probablemente pareceré
predicativo. A pesar de ello tengo fe de que este ensayo será útil.

La programación de computadoras es enseñada en cursos. Los excelentes libros: El Programador Pragmático (The Pragmatic Programmer) [Prag99], Código Completo (Code Complete) [CodeC93], Desarrollo Rápido (Rapid Development) [RDev96], y La Programación Extrema Explicada (Extreme Programming Explained)
[XP99] todos enseñan la programación de computadoras y los aspectos
más grandes de ser un buen programador. Los ensayos de Paul Graham
[PGSite] y Eric Raymond [Hacker] ciertamente deberían ser leídos antes o
junto con este artículo. Este ensayo difiere de esos excelentes
trabajos al enfatizar los problemas sociales y resumir
comprensivamente el conjunto completo de habilidades necesarias a como
yo las percibo.

En este ensayo el término jefe se refiere a quien sea que te da proyectos para hacer. Uso las palabras negocio, compañía, y tribu,
sinónimamente excepto que negocio implica hacer dinero, compañía
implica el lugar moderno de trabajo y tribu es generalmente la gente con
la que compartes lealtad.

Bienvenido a la tribu.

Capítulo 2. Principiante

Tabla de Contenido

Habilidades Personales
Aprende a Depurar
Cómo Depurar Dividiendo el Espacio del Problema
Cómo eliminar un Error
Cómo Depurar Usando una Bitácora
Cómo Comprender Problemas de Desempeño
Cómo Corregir Problemas de Desempeño
Cómo Optimizar Ciclos
Cómo Lidiar con el Costo de la E/S
Cómo Administrar la Memoria
Cómo Lidiar con Bugs Intermitentes
Cómo Aprender Habilidades de Diseño
Cómo Conducir Experimentos
Habilidades de Equipo
Por Qué la Estimación es Importante
Cómo Estimar el Tiempo de Programación
Cómo Encontrar Información
Cómo Utilizar a la Gente como Fuentes de Información
Cómo Documentar Sabiamente
Cómo Trabajar con Código Pobre
Cómo Usar el Control del Código Fuente
Cómo Probar Unidades
Toma Descansos Cuando estés Confundido
Cómo Reconocer Cuándo Ir a Casa
Cómo Lidiar con Gente Difícil

Habilidades Personales

Aprende a Depurar

La depuración es la piedra angular de ser un programador. El primer significado del verbo depurar es eliminar errores, pero el significado que realmente interesa es ver a lo interno de la ejecución de un programa mediante su examen. Un programador que no puede depurar efectivamente está ciego.

Los idealistas que piensan que el diseño, el análisis,
o la teoría de la complejidad, o lo que no es, son más fundamentales
no son programadores activos. El programador activo no vive en un
mundo ideal. Incluso si eres perfecto, estás rodeado por y debes
interactuar con código escrito por grandes compañías de software,
organizaciones como GNU, y tus colegas. La mayoría de este código es
imperfecto e imperfectamente documentado. Sin la capacidad de ganar
visibilidad dentro de la ejecución de este código el más ligero golpe
te tirará permanentemente. A menudo esta visibilidad puede ganarse
solamente mediante la experimentación, es decir, la depuración.

La depuración trata de la ejecución de programas, no
de los programas mismos. Si compras algo de una compañía de software
grande, usualmente no consigues ver el programa. Pero inclusive ahí
aparecerán lugares donde el código no se ajuste a la documentación (el
aterrizaje de toda tu máquina es un ejemplo común y espectacular), o
donde la documentación es muda. Por lo general, creas un error,
examinas el código que escribiste y no tienes una pista de cómo puede
estar ocurriendo el error. Inevitablemente, esto significa que alguna
suposición que estás haciendo no es muy correcta, o que surge alguna
condición que no anticipaste. Algunas veces el truco mágico de ver
detenidamente el código fuente funciona. Cuando no, debes depurar.

Para conseguir visibilidad dentro de la ejecución de
un programa debes ser capaz de ejecutar el código y observar algo
acerca de él. Algunas veces esto es visible, como lo que se muestra en
una pantalla, o el retardo entre dos eventos. En muchos otros casos,
involucra cosas que no necesariamente deban estar visibles, como el
estado de algunas variables dentro del código, cuáles líneas de código
están siendo actualmente ejecutadas, o si ciertas afirmaciones se
mantienen a través de una estructura de datos complicada. Esas cosas
ocultas deben ser reveladas.

Las formas comunes de ver dentro de las ‘entrañas’ de un programa en ejecución pueden ser categorizadas como:

  • Usar una herramienta de depuración,
  • Printlining — Hacer una modificación temporal al programa, típicamente adicionando líneas que impriman información, y
  • Logging — Crear una ventana permanente en la ejecución de los programas en la forma de una bitácora.

Las herramientas de depuración son maravillosas cuando
son estables y están disponibles, pero el printlining y el logging
son aún más importantes. Las herramientas de depuración a menudo se
retrasan detrás del lenguaje de desarrollo, de tal manera que en
cualquier punto del tiempo pueden no estar disponibles. Además, debido
a que la herramienta de depuración puede cambiar sutilmente la forma
en que se ejecuta el programa puede no ser siempre práctica.
Finalmente, hay algunos tipos de depuración, tal como el chequeo de una
afirmación frente a una gran estructura de datos, que requiere
escribir código y cambiar la ejecución del programa. Es bueno saber
cómo usar las herramientas de depuración cuando son estables, pero es
crítico ser capaz de emplear los otros dos métodos.

Algunos principiantes temen depurar cuando ello
requiere modificar código. Esto es comprensible—es un poquito
similar a la cirugía exploratoria. Pero tú tienes que aprender a
hurgar en el código y hacerlo saltar; tienes que aprender a
experimentar en él, y comprender que nada que le hagas temporalmente lo
empeorará. Si sientes este temor, busca un mentor—perdemos un montón
de buenos programadores en la delicada iniciación de su aprendizaje
debido a este temor.

Cómo Depurar Dividiendo el Espacio del Problema

La depuración es divertida, debido a que empieza con
un misterio. Tú piensas que debería hacer algo, pero en lugar de ello
hace algo más. No siempre es tan simple—cualesquiera ejemplos que yo
pueda dar serán forzados o artificiales comparado a lo que algunas
veces sucede en la práctica. La depuración requiere creatividad e
ingenuidad. Si hay una clave sencilla para depurar es usar en el
misterio la técnica divide y vencerás.

Supón, por ejemplo, que creaste un programa que
debería hacer diez cosas en secuencia. Cuando lo ejecutas, aterriza.
Puesto que no lo programaste para que aterrizara, ahora tienes un
misterio. Cuando observas la salida, vez que las primeras siete cosas
en la secuencia fueron ejecutadas exitosamente. Las últimas tres no
son visibles en la salida, así que ahora tu misterio es más pequeño:
‘Aterrizó en la cosa #8, #9, o #10.’

¿Puedes diseñar un experimento para ver en cuál cosa
aterrizó? Seguro. Puedes usar un depurador o podemos agregar
sentencias de impresión (o el equivalente en el lenguaje que sea en el
que estés trabajando) después de la #8 y #9. Cuando lo ejecutamos de
nuevo, nuestro misterio será más pequeño, puesto que ‘Aterrizó en la
cosa #9.’ Encuentro que mantener en mente exactamente cuál es el
misterio en cualquier punto del tiempo ayuda a mantenerse enfocado.
Cuando varias personas están trabajando juntas bajo presión en un
problema es fácil olvidar cuál es el misterio más importante.

La clave para dividir y vencer como una técnica de
depuración es la misma que para el diseño de algoritmos: mientras
hagas un buen trabajo dividiendo el misterio a la mitad, no tendrás
que dividirlo demasiadas veces, y estarás depurando rápidamente. Pero
¿cuál es la mitad de un misterio? Ahí es donde entra la verdadera
creatividad y la experiencia.

Para un verdadero principiante, el espacio de todos
los posibles errores luce como cada línea del código fuente. No tienes
la visión que más tarde desarrollarás para ver las otras dimensiones
del programa, tales como el espacio de líneas ejecutadas, las
estructuras de datos, el manejo de la memoria, la interacción con
código foráneo, el código que es riesgoso, y el código que es simple.
Para el programador experimentado, esas otras dimensiones forman un
imperfecto pero muy útil modelo mental de todas las cosas que pueden ir
mal. Tener ese modelo mental es lo que le ayuda a uno a encontrar la
mitad del misterio efectivamente.

Una vez que has subdividido eventualmente el espacio
de todo lo que puede ir mal, debes intentar decidir en cuál espacio
yace el error. En el caso simple dónde está el misterio: ‘¿Cuál única
línea desconocida hace aterrizar a mi programa?’, puedes preguntarte a
ti mismo: ‘¿Se ejecuta la línea desconocida antes o después de esa
línea que juzgo debe ser ejecutada cerca de la mitad del programa en
ejecución?’ Usualmente no serás tan afortunado como para saber que el
error existe en una única línea, o aún en un único bloque. A menudo el
misterio será más o menos como: ‘O hay un puntero en ese gráfico que
apunta al nodo equivocado, o mi algoritmo que agrega las variables en
ese gráfico no funciona.’ En ese caso puede que tengas que escribir un
pequeño programa para chequear que los punteros en el gráfico son
todos correctos a fin de decidir cuál parte del misterio subdividido
puede ser eliminada.

Cómo eliminar un Error

He separado intencionalmente el acto de examinar la
ejecución de un programa del acto de corregir un error. Pero por
supuesto, depurar también significa eliminar el bug.
Idealmente tendrás perfecta comprensión del código y alcanzarás un
momento ‘¡Ajá!’ donde perfectamente verás el error y cómo corregirlo.
Pero debido a que tu programa a menudo usará sistemas
insuficientemente documentados en los cuales no tienes visibilidad, esto
no siempre es posible. En otros casos el código es tan complicado que
tu comprensión no puede ser perfecta.

Al corregir un bug, deseas hacer el más pequeño cambio
que corrija el bug. Puedes ver otras cosas que necesitan mejoría;
pero no las corrijas al mismo tiempo. Intenta emplear el método
científico de cambiar una y solamente una cosa a la vez. El mejor
proceso para esto es ser capaz de reproducir fácilmente el bug, luego
poner tu corrección en su lugar, y después reejecutar el programa y
observar que el bug no existe más. Por supuesto, algunas veces debe ser
cambiada más de una línea, pero aún deberías aplicar conceptualmente
un único cambio atómico para corregir el bug.

A veces, hay en realidad varios bugs que se ven como
uno. Es tu trabajo definirlos y corregirlos uno a la vez. Algunas
veces no es claro qué debería hacer el programa o qué intentó el autor
original. En ese caso, debes ejercitar tu experiencia y tu juicio y
asignar tu propio significado al código. Decide qué debería hacer, y
coméntalo o clarifícalo de alguna forma y luego haz que el código
concuerde con tu significado. Esta es una habilidad intermedia o
avanzada que es a veces más difícil de adquirir que el escribir la
función original en primera instancia, pero el mundo real a menudo es
desordenado. Puede que tengas que corregir un sistema que no puedes
reescribir.

Cómo Depurar Usando una Bitácora

El logging es la práctica de escribir un sistema de tal manera que produzca una secuencia de registros informativos, llamado bitácora (log). El printlining
consiste en producir tan solo una bitácora simple, usualmente
temporal. Los verdaderos principiantes deben entender y usar bitácoras
porque su conocimiento de la programación es limitado; los arquitectos
de sistemas deben comprender y usar bitácoras debido a la complejidad
del sistema. La cantidad de información que provea la bitácora debería
ser configurable, idealmente mientras el programa está en ejecución.
En general, las bitácoras ofrecen tres ventajas básicas:

  • Las bitácoras pueden proveer información útil sobre bugs que son
    difíciles de reproducir (tales como los que ocurren en el ambiente de
    producción pero que no pueden ser reproducidos en el ambiente de
    prueba).
  • Las bitácoras pueden proveer estadísticas y datos relevantes para
    el desempeño, tales como el tiempo que pasa entre sentencias.
  • Cuando son configurables, las bitácoras permiten que se capture
    información general a fin de depurar problemas específicos no
    anticipados sin tener que modificar y/o reimplementar el código lo
    suficiente como para lidiar con esos problemas específicos.

La cantidad de salida a poner en la bitácora es
siempre un compromiso entre información y brevedad. Demasiada
información hace la bitácora costosa y produce ceguera de desplazamiento,
haciendo difícil el encontrar la información que necesitas. Muy poca
información y puede que no contenga lo que necesitas. Por esta razón,
hacer configurable lo que es salida para la bitácora es muy útil.
Típicamente, cada registro en la bitácora identificará su posición en el
código fuente, el hilo que lo ejecutó si es aplicable, la hora
precisa de ejecución, y, comúnmente, una pieza útil de información
adicional, tal como el valor de alguna variable, la cantidad de
memoria libre, el número de objetos de datos, etc. Esas sentencias de
la bitácora están diseminadas a través del código fuente pero
particularmente en los puntos de las funcionalidades más grandes y
alrededor del código riesgoso. A cada sentencia se le puede asignar un
nivel y solamente generará un registro si el sistema está actualmente
configurado para generar salida de ese nivel. Deberías diseñar las
sentencias bitácora para manejar problemas que anticipes. Anticipa la
necesidad de medir el desempeño.

Si tienes una bitácora permanente, el printlining
puede hacerse ahora en términos de los registros de la bitácora, y
algunas de las sentencias de depuración probablemente serán añadidas
permanentemente al sistema de registro de la bitácora.

Cómo Comprender Problemas de Desempeño

Aprender a comprender el desempeño de un sistema en
ejecución es inevitable por la misma razón que tiene el aprender a
depurar. Incluso si el código que comprendes perfectamente es
justamente el costo del código que escribes, tu código hará llamadas a
lo interno de otros sistemas de software sobre los que tienes poco
control o visibilidad. Sin embargo, en la práctica los problemas de
desempeño son un poco diferentes y un poco más fáciles que la depuración
en general.

Supón que tú o tus clientes consideran que un sistema o
un subsistema es muy lento. Antes de que intentes hacerlo más rápido,
debes construir un modelo mental de por qué es lento. Para hacer esto
puedes usar una herramienta de perfilación o una buena bitácora para
determinar realmente dónde están siendo gastados el tiempo y los otros
recursos. Hay un famoso dicho de que el 90% del tiempo será gastado
en 10% del código. Yo añadiría a eso la importancia de los costos de
entrada/salida (E/S) a los tópicos de desempeño. A menudo la mayor
parte del tiempo se gasta en E/S de una forma u otra. Encontrar la E/S
costosa y el costoso 10% del código es un buen primer paso para
construir tu modelo mental.

Hay muchas dimensiones relacionadas al desempeño de un
sistema computacional, y muchos recursos consumidos. El primer
recurso a medir es el tiempo del reloj de pared, el tiempo
total que pasa para la computación. Registrar en la bitácora el tiempo
del reloj de pared es particularmente valioso debido a que él puede
informar acerca de circunstancias impredecibles que surgen en
situaciones donde otra forma de perfilación es impráctica. Sin embargo,
esto podría no siempre representar toda la escena. Algunas veces algo
que toma un poco más de tiempo pero que no quema tantos segundos del
procesador será mucho mejor con lo que tienes que lidiar realmente en
el ambiente computacional. Similarmente, la memoria, el ancho de banda
de la red, la base de datos u otros accesos a servidores pueden, al
final, ser mucho más costosos que los segundos del procesador.

La contención de recursos compartidos que están
sincronizados puede causar estancamiento e inanición. El estancamiento
es la incapacidad para proceder debido a la inapropiada
sincronización o demanda de recursos. La inanición es la falla al
calendarizar apropiadamente un componente. Si puede ser del todo
anticipado, es mejor tener una forma de medir esta contención desde el
inicio de tu proyecto. Aún si esta contención no ocurre, es muy útil
ser capaz de afirmar eso con confianza.

Cómo Corregir Problemas de Desempeño

La mayoría de los proyectos de software pueden hacerse
con relativamente poco esfuerzo de 10 a 100 veces más rápido de lo
que son la primera vez que son liberados. Bajo la presión del tiempo
de mercadeo, es tan sabio como efectivo elegir una solución que
obtenga el trabajo hecho simple y rápidamente, pero menos eficiente
que alguna otra solución. Sin embargo, el desempeño es una parte de la
usabilidad, y a menudo debe eventualmente ser considerado más
cuidadosamente.

La clave para mejorar el desempeño de un sistema muy complicado es analizarlo lo suficientemente bien para encontrar los cuellos de botella,
o lugares donde se consumen la mayoría de los recursos. No tiene
mucho sentido optimizar una función que cuenta solamente para el 1%
del tiempo de cómputo. Como una regla de ganadores deberías pensar
cuidadosamente antes de hacer algo a menos que pienses que va a hacer
al sistema o a una parte significativa de él al menos dos veces más
rápida. Usualmente hay una forma de hacer esto. Considera los tests y
los esfuerzos de aseguramiento de la calidad que tu cambio requerirá.
Cada cambio trae una prueba aparejada con él, de tal manera que es mucho
mejor tener unos cuantos grandes cambios.

Después de que has hecho una mejora de dos pliegues en
algo, necesitas al menos repensar y quizá reanalizar para descubrir
el siguiente cuello de botella más costoso en el sistema, y atacar eso
para obtener otra mejora de dos pliegues.

A menudo, los cuellos de botella en el desempeño serán
un ejemplo de contar vacas mediante el conteo de piernas y dividiendo
entre cuatro, en lugar de contar cabezas. Por ejemplo, he cometido
errores tales como fallar al proveer un sistema de base de datos
relacional con un índice apropiado sobre una columna que observé
mucho, lo cual probablemente la hizo al menos 20 veces más lenta.
Otros ejemplos incluyen hacer E/S innecesaria en ciclos internos, dejar
sentencias de depuración que no se necesitaban más, asignación de
memoria innecesaria, y, en particular, uso inexperto de bibliotecas y
otros subsistemas que a menudo están pobremente documentados con
respecto al desempeño. Este tipo de mejora es a veces llamada fruta de cuelgue bajo, que significa que puede ser fácilmente elegida para proveer algún beneficio.

¿Qué haces cuando empiezas a quedarte sin frutas de
cuelgue bajo? Bien, puedes alcanzar las más altas, o derribar el
árbol. Puedes continuar haciendo pequeñas mejoras o puedes rediseñar
seriamente un sistema o un subsistema. (Esta es una gran oportunidad
para usar tus habilidades de buen programador, no solamente en el
nuevo diseño sino también en convencer a tu jefe que esta es una buena
idea.) Sin embargo, antes de que argumentes por el rediseño de un
subsistema, deberías preguntarte a ti mismo si tu propuesta lo hará o no
de cinco a diez veces mejor.

Cómo Optimizar Ciclos

A veces encontrarás ciclos, o funciones recursivas,
que toman un largo tiempo para ejecutarse y son cuellos de botella en
tu producto. Antes de que intentes hacer el ciclo un poco más rápido,
invierte unos pocos minutos en considerar si hay forma de eliminarlo
completamente. ¿Funcionaría un algoritmo diferente? ¿Podrías computar
eso mientras computas algo más? Si no puedes hallar una manera de
mejorarlo, entonces puedes optimizar el ciclo. Esto es simple: mueve
material fuera. Al final, esto requerirá no solamente ingenuidad sino
también una comprensión del costo de cada tipo de sentencia y
expresión. He aquí algunas sugerencias:

  • elimina operaciones de punto flotante.
  • No asignes nuevos bloques de memoria innecesariamente.
  • Pliega constantes juntas.
  • Mueve E/S a un búfer.
  • Trata de no dividir.
  • Trata de no hacer costosas conversiones de tipo.
  • Mueve un puntero en lugar de recomputar índices.

El costo de casa una de esas operaciones depende de tu
sistema específico. En algunos sistemas los compiladores y el
hardware hacen esas cosas por ti. El código claro y eficiente es mejor
que el código que requiere la comprensión de una plataforma
particular.

Cómo Lidiar con el Costo de E/S

Para un montón de problemas, los procesadores son
rápidos comparados al costo de comunicarse con un dispositivo de
hardware. Este costo es usualmente abreviado E/S, y puede incluir
costo de red, E/S de disco, consultas de bases de datos, E/S de
archivo, y otro uso del algún hardware no muy cercano al procesador.
Por lo tanto construir un sistema rápido es a menudo más una cuestión
de mejorar la E/S que mejorar el código en algún ciclo ajustado, e
incluso mejorar un algoritmo.

Hay dos técnicas muy fundamentales para mejorar la
E/S: el cacheo y la representación. El cacheo es evitar la E/S
(generalmente evitando la lectura de algún valor abstracto) mediante
el almacenamiento local de una copia de ese valor de manera que no se
ejecuta ninguna E/S para obtener el valor. La primer clave para el
cacheo es hacer claro como el cristal cuál dato es el maestro y cuáles son las copias.
Hay solamente un maestro— punto. El cacheo trae consigo el peligro
de que la copia algunas veces no pueda reflejar los cambios
instantáneamente al maestro.

La representación es el método de hacer la E/S más
barata representando los datos más eficientemente. Esto está a menudo
en tensión con otras demandas, como la legibilidad humana y la
portabilidad.

Las representaciones pueden a menudo ser mejoradas por
un factor de dos o tres de su primera implementación. Las técnicas
para hacer esto incluyen usar una representación binaria en lugar de
una que sea legible para los humanos, transmitir un diccionario de
símbolos junto con los datos de tal manera que a la larga los símbolos
no tengan que ser codificados, y, en el extremo, cosas como la
codificación Huffman.

Una tercer técnica que es a veces posible es mejorar
la localidad de referencia empujando la computación más cerca de los
datos. Por ejemplo, si estás leyendo algunos datos de una base de
datos y computando algo simple de ella, tal como una sumatoria, trata
de hacer que el servidor de la base de datos lo haga por ti. Esto es
altamente dependiente del tipo de sistema con el que estés trabajando,
pero deberías explorarlo.

Cómo Administrar la Memoria

La memoria es un recurso precioso del que no puedes
darte el lujo de adolecer. Puedes ignorarla por un momento pero
eventualmente tendrás que decidir cómo administrarla.

El espacio que necesita para persistir más allá del alcance de una sencilla subrutina es a menudo llamado heap asignado. Un trozo de memoria es inútil, y por lo tanto basura,
cuando nada lo referencia. Dependiendo del sistema que uses, puede
que tengas que desasignar explícitamente la memoria tu mismo cuando
está a punto de convertirse en basura. Muy a menudo puedes ser capaz
de usar un sistema que proporcione un recolector de basura. Un
recolector de basura nota la basura y libera su espacio sin ninguna
acción requerida por el programador. La recolección de basura es
maravillosa: reduce los errores e incrementa la brevedad del código y
la concisión de forma barata. Úsala cuando puedas.

Pero aún con la recolección de basura, puedes llenar
toda la memoria con basura. Un error clásico es usar una tabla hash
como un caché y olvidar eliminar las referencias en dicha tabla.
Puesto que las referencias se mantienen, el referente es no
recolectable sino inútil. Esto es llamado una fuga de memoria.
Debes observar y corregir temprano las fugas de memoria. Si tienes
tiempo de estar corriendo sistemas puede que la memoria nunca se agote
durante las pruebas pero será agotada por el usuario.

La creación de nuevos objetos es moderadamente costosa
en cualquier sistema. La memoria asignada directamente en las
variables locales de una subrutina, sin embargo, es usualmente barata
debido a que la política para liberarla puede ser muy simple. Deberías
evitar la creación innecesaria de objetos.

Un caso importante ocurre cuando puedes definir un
límite superior en el número de objetos que necesitarás a la vez. Si
todos esos objetos toman la misma cantidad de memoria, puedes ser
capaz de asignar un único bloque de memoria, o un búfer, para
contenerlas todas. Los objetos que necesitas pueden ser ubicados y
liberados dentro de este búfer en un patrón de rotación fijo, por lo
cual esto es llamado a veces un búfer circular. Esto es usualmente más
rápido que la asignación heap.

Algunas veces tienes que liberar explícitamente el
espacio asignado de tal forma que pueda ser reasignado en lugar de
confiar en la recolección de basura. Luego debes aplicar
cuidadosamente la inteligencia para cada trozo de memoria asignada y
diseñar un método para que sea desasignada en el momento apropiado. El
método puede diferir para cada tipo de objeto que crees. Debes
asegurarte que cada ejecución de una operación de asignación de
memoria coincida eventualmente con una desasignación de memoria. Esto
es tan difícil que los programadores a menudo implementan simplemente
una forma rudimentaria de recolección de basura, tal como un conteo de
referencia, para hacer esto por ellos.

Cómo Lidiar con Bugs Intermitentes

El bug intermitente es primo del escorpión espacial
invisible de 50 pies. Esta pesadilla ocurre tan raras veces que es
difícil de observar, pero lo suficientemente a menudo como para que no
pueda ser ignorado. No puedes depurarlo porque no puedes encontrarlo.

Aunque después de 8 horas empezarás a dudarlo, el bug
intermitente tiene que obedecer a las mismas leyes de la lógica que
todo lo demás. Lo que lo hace difícil es que ocurre solamente bajo
condiciones desconocidas. Trata de registrar las circunstancias bajo
las cuales ocurre el bug, de tal manera que puedas adivinar realmente
en qué yace la variabilidad. La condición puede estar relacionada a
los valores de los datos, tales como ‘Esto sólo sucede cuando
introducimos Wyoming como valor.’ Si eso no es la fuente de la
variabilidad, la próxima sospecha debería ser la concurrencia
inapropiadamente sincronizada.

Trata, trata, trata de reproducir el bug de una forma
controlada. Si no puedes reproducirlo, configura una trampa para él
mediante la construcción de un sistema de registro de sucesos
(logging), una especial si tienes que hacerlo, que pueda registrar lo
que supones que necesitas cuando realmente ocurre. Resígnate a ti
mismo a que si el bug solamente ocurre en producción y no a tu antojo,
este sea quizá un largo proceso. Las pistas que obtengas de la bitácora
puede que no proporcionen la solución pero pueden darte suficiente
información para mejorar el registro de sucesos. El sistema mejorado
de registro de sucesos puede requerir un largo tiempo para estar en
producción. Luego, tienes que esperar a que reaparezca el bug para
obtener más información. Este círculo puede seguir por algún tiempo.

El bug intermitente más estúpido que he creado fue en
una implementación multi-hilo de un lenguaje de programación funcional
para un proyecto de clase. Me había asegurado cuidadosamente de la
correcta evaluación concurrente del programa funcional y la buena
utilización de todas las CPUs disponibles (ocho, en este caso).
Simplemente olvidé sincronizar el recolector de basura. El sistema
podría correr un largo tiempo, a menudo finalizando cualquier tarea que
comenzara, antes de que algo notable fuese mal. Estoy avergonzado al
admitir que había comenzado a cuestionar al hardware antes de que mi
error me pusiera en evidencia.

En el trabajo recientemente teníamos un bug
intermitente que nos tomó varias semanas encontrar. Tenemos servidores
de aplicación multi-hilados en Java™ detrás de servidores web Apache™.
Para mantener cambios de página rápidos, hacemos toda la E/S en
pequeños conjuntos de cuatro hilos separados que son diferentes de los
hilos cambia páginas. Aparentemente cada cierto tiempo esos hilos se
‘clavaban’ y cesaban de hacer cualquier cosa útil, hasta que nuestro
registro de sucesos nos permitió determinarlo, por horas. Puesto que
teníamos cuatro hilos, esto no era en sí mismo un problema gigante—a
menos que los cuatro se clavaran. Luego esas colas vaciadas por esos
hilos rápidamente llenarían toda la memoria disponible y hacían
aterrizar nuestro servidor. Nos tomó cerca de una semana entender
esto, y aún no sabíamos qué lo causaba, cuándo sucedía, e incluso qué
estaban haciendo los hilos cuando se ‘clavaban’.

Esto ilustra algunos riesgos asociados con software de
terceros. Estábamos usando una pieza de código licenciada que eliminó
las etiquetas HTML del texto. Debido a su lugar de origen nos
referíamos a él entrañablemente como ‘el stripper francés.’ Aunque
teníamos el código fuente (¡bondadosa gracia!) no lo habíamos
estudiado cuidadosamente hasta cuando activamos el registro de sucesos
en nuestros servidores que finalmente nos dimos cuenta que los hilos
del email estaban clavando en el stripper francés.

El stripper se desempeñaba bien excepto en algunos
largos e inusuales tipos de textos. En esos textos, el código era
cuadrático o peor. Esto significa que el tiempo de procesamiento era
proporcional al cuadrado de la longitud del texto. Si esos textos
hubieran ocurrido comúnmente, hubiésemos encontrado el bug de
inmediato. Si no hubieran ocurrido del todo, nunca hubiésemos tenido un
problema. Como suele suceder, nos tomó semanas para finalmente
comprender y resolver el problema.

Cómo Aprender Habilidades de Diseño

Para aprender cómo diseñar software, estudia la acción
de un mentor estando físicamente presente cuando él está diseñando.
Luego estudia piezas de software bien escritas. Después de eso, puedes
leer algunos libros sobre las últimas técnicas de diseño.

Luego debes hacerlo tú mismo. Empieza con un proyecto
pequeño. Cuando finalmente hayas terminado, considera cómo falló o
cómo tuvo éxito el diseño y cómo divergiste de tu concepción original.
Luego muévete hacia proyectos más grandes, preferentemente en
conjunto con otras personas. El diseño es una cuestión de juicio que
toma años adquirir. Un programador inteligente puede aprender los
fundamentos adecuadamente en dos meses y puede mejorar a partir de
ahí.

Es natural y útil desarrollar tu propio estilo, pero
recuerda que el diseño es un arte, no una ciencia. La gente que
escribe libros sobre el tema tiene un marcado interés en hacerlo
parecer científico. No te vuelvas dogmático acerca de estilos de
diseño particulares.

Cómo Conducir Experimentos

El gran Edsger Dijkstra ha explicado elocuentemente
que la Ciencia de la Computación no es una ciencia experimental
[ExpCS] y no depende de computadoras electrónicas. Como él lo señaló
refiriéndose a los 1960s [Knife],

…el daño estaba hecho: el tópico se volvió
conocido como “la ciencia de la computadora”—lo cual, de hecho, es
como referirse a la cirugía como “la ciencia del cuchillo” — y fue
firmemente implantado en las mentes de las personas que la ciencia de
la computación es acerca de máquinas y sus equipos periféricos.

La programación no debe ser una ciencia experimental,
pero la mayoría de los programadores activos no tienen el lujo de
encajar en lo que Dijkstra quiso dar a entender por ciencia de la
computación. Debemos trabajar en el campo de la experimentación, igual
que algunos, pero no todos, los físicos. Si dentro de treinta años la
programación puede ser realizada sin experimentación, será un gran
logro para la Ciencia de la Computación.

Los tipos de experimentos que tendrás que realizar incluyen:

  • Probar sistemas con pequeños ejemplos para verificar que se
    ajustan a la documentación o para comprender sus respuestas cuando no
    hay documentación,
  • Probar pequeños cambios en el código para ver si realmente corrigen un bug,
  • Medir el desempeño de un sistema bajo dos diferentes condiciones
    debido al conocimiento imperfecto de sus características de desempeño,
  • Chequear la integridad de los datos, y
  • Recolectar estadísticas que podrían dar pistas para la solución de bugs dificultosos o difíciles de repetir.

No creo que en este ensayo pueda explicar el diseño de
experimentos; tendrás que estudiar y practicar. Sin embargo, puedo
ofrecerte dos pequeños consejos.

Primero, trata de ser muy claro acerca de tu
hipótesis, o la afirmación que estás tratando de probar. También ayuda
el escribir la hipótesis, especialmente si te encuentras a ti mismo
confundido o estás trabajando con otros.

A menudo te encontrarás a ti mismo teniendo que
diseñar una serie de experimentos, cada uno de los cuales está basado
en el conocimiento ganado a partir del último. Por lo tanto, deberías
diseñar tus experimentos para que proporcionen la mayor información
posible. Desafortunadamente, esto está en conflicto con el mantener
cada experimento simple—tendrás que desarrollar este juicio a través
de la experiencia.

Habilidades de Equipo

Por Qué la Estimación es Importante

Tener un sistema de software funcional en uso activo
tan rápidamente como sea posible no solamente requiere planear el
desarrollo, sino también planear la documentación, la implementación y
el mercadeo. En un proyecto comercial ello también requiere ventas y
finanzas. Sin la previsibilidad del tiempo de desarrollo, es imposible
planear esas cosas efectivamente.

La buena estimación proporciona previsibilidad. Los
administradores la aman, tan bien como deberían. El hecho de que es
imposible, tanto teórica como prácticamente, el predecir exactamente
cuánto tiempo tomará desarrollar software está a menudo perdido en los
administradores. Se nos pide hacer este imposible todo el tiempo, y
debemos encararlo honestamente. Sin embargo, sería deshonesto no
admitir la imposibilidad de esta tarea, y cuando sea necesario,
explicarla. Hay mucho espacio para los problemas de comunicación sobre
los estimados, puesto que la gente tiene una sorprendente tendencia a
pensar deseosamente que la oración:

Estimo que, si comprendo realmente el
problema, hay 50% de probabilidades de que estará listo en cinco
semanas (si nadie nos molesta durante ese tiempo).

realmente significa:

Prometo tenerlo hecho en cinco semanas.

Este común problema de interpretación requiere que
explícitamente discutas qué significa el estimado con tu jefe o
cliente como si ellos fueran unos simplones. Replantea tu
suposiciones, no importa cuán obvias te parezcan.

Cómo Estimar el Tiempo de Programación

La estimación toma práctica. También conlleva trabajo.
Requiere tanto trabajo que puede ser una buena idea estimar el tiempo
que tomará hacer el estimado, especialmente si se te pide estimar
algo grande.

Cuando se nos pide proporcionar un estimado de algo
grande, la cosa más honesta por hacer es detenerte. La mayoría de los
ingenieros son entusiastas y propensos a agradar, y el que detengas
ciertamente desagradará al detenido. Pero un estimado al vuelo
probablemente no será preciso ni honesto.

Mientras estás en standby, puede que sea posible
considerar el hacer un prototipo de la tarea. Si la presión política
lo permite, esta es la forma más exacta de producir el estimado, y
constituye un progreso real.

Cuando no es posible tomarse tiempo para alguna
investigación, deberías establecer primero el significado del estimado
muy claramente. Replantea ese significado como la primera y última
parte de tu estimado escrito. Prepara un estimado escrito
descomponiendo la tarea en subtareas progresivamente más pequeñas
hasta que cada una de esas pequeñas tareas no exceda más que un día;
idealmente a la mayoría en duración. Lo más importante es no dejar nada
fuera. Por ejemplo, la documentación, la prueba, el tiempo para la
planeación, el tiempo para comunicarse con otros grupos, y las fechas
de vacaciones son también todas muy importantes. Si pasas una parte de
cada día lidiando con cabezaduras, incluye un ítem para eso en el
estimado. Ello le da a tu jefe la visibilidad de en qué está usándose
tu tiempo hasta el mínimo, y podría procurarte más tiempo.

Conozco buenos ingenieros que rellenan estimados
implícitamente, pero te recomiendo que no lo hagas. Uno de los
resultados de rellenar es confiar en que pueden reducirte. Por
ejemplo, un ingeniero podría estimar tres días para una tarea que
realmente piensa que tomará un día. El ingeniero puede planear el
pasar dos días documentándolo, o dos días trabajando en algún otro
proyecto útil. Pero será visible que la tarea fue hecha en solamente
un día (si resulta ser así), y nacerá la apariencia de flojera o
sobreestimación del tiempo. Es mucho mejor brindar una apropiada
visibilidad de lo que realmente estás haciendo. Si la documentación
toma dos veces más tiempo que la codificación y el estimado así lo
dice, se gana una tremenda ventaja al hacer esto visible al
administrador.

En su lugar rellena explícitamente. Si una tarea
probablemente tomará un día—pero podría tomar diez si tu método no
funciona—has notar esto de algún modo en el estimado si puedes; si
no, al menos haz un promedio ponderado por tus estimados de las
probabilidades. Cualquier factor de riesgo que puedas identificar y
asignarle un estimado debería ir en el calendario. Es poco probable
que una persona pueda estar enferma en alguna semana dada. Pero un
proyecto grande con muchos ingenieros tendrá algún tiempo de enfermedad;
al igual que tiempo para vacaciones. ¿Y qué hay de la probabilidad de
un seminario de entrenamiento obligatorio para toda la compañía? Si
puede ser estimado, inclúyelo. Existen por supuesto, desconocidos
desconocidos, o unk-unks (del inglés unknown-unknowns). Los
unk-unks por definición no pueden ser estimados individualmente.
Puedes intentar crear un ítem global para todos los unk-unks, o
manejarlos de alguna otra forma para que puedas comunicárselo a tu
jefe. No puedes, sin embargo, permitir que tu jefe olvide que ellos
existen, y es endiabladamente fácil para un estimado convertirse en un
programa sin que sean considerados los unk-unks.

En un entorno de equipo, deberías tratar de tener a la
gente que hará el trabajo de elaborar el estimado, y deberías
intentar tener un consenso con el equipo en general sobre los
estimados. La gente varía ampliamente en habilidad, experiencia,
preparación, y confianza. La calamidad golpea cuando un programador
fuerte estima para él mismo y luego se le mantiene este estimado a los
programadores débiles. El hecho de tener de acuerdo al equipo completo
en una base de línea por línea del estimado clarifica la comprensión
del equipo, al igual que permite la oportunidad para la reasignación
táctica de recursos (por ejemplo, intercambiar carga de trabajo de
miembros del equipo más débiles a otros más fuertes).

Si existen grandes riesgos que no puedan ser
evaluados, es tu deber establecerlos lo suficientemente fuerte como
para que tu administrador no se comprometa a ellos y luego se
avergüence cuando sucedan los riesgos. Hopefully en tales casos se
hará lo que sea necesario para disminuir el riesgo.

Si puedes convencer a tu compañía de usar la Programación Extrema, solamente tendrás que estimar cosas relativamente pequeñas, y esto es tan divertido como productivo.

Cómo Encontrar Información

La naturaleza de lo que necesitas saber determina cómo deberías encontrarlo.

Si necesitas información sobre cosas concretas
que son objetivas y fáciles de verificar, por ejemplo el último nivel
de parcheo de un producto software, pregunta cortésmente a un gran
número de personas buscándolas en la Internet o colocando mensajes en
un grupo de discusión. No busques en la Internet algo que sabe o tiene
un dejo de opinión o interpretación subjetiva: el nivel de tonterías
en las que confiar es demasiado alto.

Si necesitas conocimiento general sobre algo subjetivo
como la historia o lo que la gente ha pensado acerca de ella, ve a la
biblioteca (el edificio físico en el cual hay libros almacenados).
Por ejemplo, para aprender sobre matemática u hongos o misticismo, ve a
la biblioteca.

Si necesitas saber cómo hacer algo que no es trivial
consigue dos o tres libros sobre el tema y léelos. Podrías aprender
cómo hacer algo trivial, como instalar un paquete de software, desde
la Internet. Puedes incluso aprender cosas importantes, como buenas
técnicas de programación, pero puedes fácilmente pasar más tiempo
buscando y ordenando los resultados e intentar adivinar la autoridad
de los resultados que lo que tomaría leer la parte pertinente de un
sólido libro.

Si necesitas información que nadie más podría esperarse que sepa
por ejemplo, ‘¿funciona esta nueva marca de software sobre conjuntos
de datos gigantescos?’, aún debes buscar en la Internet y la
biblioteca. Después de que esas opciones estén completamente agotadas,
puedes diseñar un experimento para comprobarlo.

Si quieres una opinión o un juicio de valor que tome
en cuenta alguna circunstancia única, habla con un experto. Por
ejemplo, si quieres saber si es una buena idea o no el construir un
sistema de manejo de base de datos en LISP, deberías hablar con un
experto en LISP y a un experto en bases de datos.

Si quieres saber qué tan probable es que
exista un algoritmo más rápido para una aplicación particular que no
haya sido publicado, habla con alguien que trabaje en ese campo.

Si quieres hacer una decisión personal que solamente tú puedes hacer
como si deberías o no empezar un negocio, intenta poner por escrito una
lista de argumentos a favor y en contra de la idea. Si eso falla,
considera la adivinación. Supón que has estudiado la idea desde todos
los ángulos, haz hecho toda tu tarea en casa, y analizado en tu mente
todas las consecuencias y pros y contras, y todavía estás indeciso.
Ahora debes seguir a tu corazón y decirle a tu cerebro que se calle.
La multitud de técnicas de adivinación disponibles son muy útiles para
determinar tus propios deseos semiconscientes, puesto que cada uno de
ellos presenta un patrón aleatorio y completamente ambiguo al que tu
propio subconsciente asignará significado.

Cómo Utilizar a la Gente como Fuentes de Información

Respeta el tiempo de cada persona y balancéalo frente
al tuyo propio. El hacer a alguien una pregunta conlleva mucho más que
sólo recibir la respuesta. La persona aprende sobre ti, tanto al
disfrutar de tu presencia como al escuchar la pregunta particular. Tu
aprendes sobre la persona de la misma forma, y puedes aprender la
respuesta que buscas. Esto es usualmente mucho más importante que tu
pregunta.

Sin embargo, el valor de esto disminuye entre más lo
repitas. Estás, después de todo, usando la comodidad más preciada que
una persona tiene: su tiempo. Los beneficios de la comunicación deben
ser sopesados frente a los costos. Además, los costos y los beneficios
particulares derivados difieren de persona a persona. Creo firmemente
que un ejecutivo de 100 personas debería invertir cinco minutos de su
tiempo al mes hablando con cada persona de su organización, lo cual
representaría cerca del 5% de su tiempo. Pero diez minutos podrían ser
demasiados, y cinco es demasiado si tienen mil empleados. La cantidad
de tiempo que inviertes hablando con cada persona en tu organización
depende de su rol (más que de su posición). Deberías hablar con tu
jefe más que con el jefe de tu jefe, pero deberías hablar un poco con
el jefe de tu jefe. Puede ser incómodo, pero creo que tienes el deber
de hablar un poquito con todos tus superiores, cada mes, no importa de
qué.

La regla básica es que todos se benefician de hablar
un poquito contigo, y entre más hablen contigo, menos beneficio
deriva. Es tu trabajo proporcionarles ese beneficio, y obtener el
beneficio de comunicarte con ellos, manteniendo el beneficio en
balance con el tiempo invertido.

Es importante respetar tu propio tiempo. Si hablas con
alguien, incluso si ello les costará tiempo, te ahorrará una gran
cantidad de tiempo, entonces deberías hacerlo a menos que pienses que
su tiempo es más valioso que el tuyo, para la tribu, por ese factor.

Un raro ejemplo de esto es el interno de verano. No
puede esperarse que un interno de verano en una posición altamente
técnica logre mucho; puede esperarse de él que importune el infierno
de todos ahí. Entonces ¿por qué es tolerado? Porque los importunados
están recibiendo algo importante del interno. Ellos tienen la
oportunidad de enseñar algo. Tienen la oportunidad de escuchar algunas
ideas nuevas, quizá; Tienen la oportunidad de ver las cosas desde una
perspectiva diferente. También pueden estar intentando reclutar al
interno, pero aún si este no es el caso hay mucho que ganar.

Deberías pedirle a la gente un poco de su sabiduría y
juicio las veces que honestamente creas que tienen algo que decir.
Esto los adula y tu aprenderás algo y les enseñarás algo. Un buen
programador no necesita a menudo el consejo de un Vicepresidente de
Ventas, pero si alguna vez lo necesitas, asegúrate de pedirlo. Una vez
pedí escuchar unas pocas llamadas de ventas para comprender mejor el
trabajo de nuestro staff de ventas. Esto no tomó más de 30 minutos pero
pienso que el pequeño esfuerzo causó una impresión en las fuerzas de
ventas.

Cómo Documentar Sabiamente

La vida es demasiado corta como para escribir basura
que nadie leerá; si escribes basura, nadie la leerá. Por lo tanto un
poco de buena documentación es mejor. Los administradores a menudo no
comprenden esto, debido a que aún la mala documentación les da un
falso sentido de seguridad de que ellos no son dependientes de sus
programadores. Si alguien insiste absolutamente en que escribas
verdadera documentación inútil, di «si» y calladamente empieza a
buscar un mejor empleo.

No hay nada tan efectivo como poner un estimado
preciso de la cantidad de tiempo que tomará producir buena
documentación en un estimado para reducir la demanda de documentación.
La verdad es fría y dura: la documentación, como las pruebas, pueden
tomar períodos de tiempo mucho más largos que el desarrollo de código.

Escribir buena documentación es, antes de todo,
cuestión de buena escritura. Te sugiero buscar libros sobre escritura,
estudiarlos y practicar. Pero incluso si eres un mal escritor o
tienes un pobre dominio del lenguaje en el cual debes documentar, la
Regla de Oro es todo lo que necesitas: «Haz a los otros lo que te
gustaría que te hicieran a ti.» Toma tiempo pensar realmente acerca de
quién estará leyendo tu documentación, qué necesitan sacar de ella, y
cómo puedes enseñarles eso. Si haces esto, serás un escritor de
documentación por encima del promedio, y un buen programador.

Cuando se trata de documentar código por sí mismo,
como algo opuesto a producir documentos que realmente puedan ser
leídos por no programadores, los mejores programadores que he conocido
tienen un sentimiento universal: escribe código autoexplicativo y
solamente documenta el código en los lugares que no puedes hacerlo
claro mediante el código mismo. Hay dos buenas razones para esto.
Primero, cualquiera que necesite ver la documentación a nivel de código
será capaz en la mayoría de los casos y preferirá leer el código de
todas formas. Reconocidamente, esto parece más fácil para el
programador experimentado que para el principiante. Más importante sin
embargo, es que el código y la documentación no pueden ser
inconsistentes si no hay documentación. El código fuente en el peor de
los casos puede estar equivocado y confuso. La documentación, si no
está escrita perfectamente, puede mentir, y eso es mil veces peor.

Esto no facilita las cosas para el programador
responsable. ¿Cómo escribe uno código autoexplicativo? ¿Qué significa
incluso eso? Ello significa:

  • Escribir código sabiendo que alguien tendrá que leerlo;
  • Aplicar la regla de oro;
  • Elegir una solución que sea directa, incluso si cuentas con otra solución más rápida;
  • Sacrificar pequeñas optimizaciones en lugar de ofuscar el código;
  • Pensar en el lector e invertir algo de tu precioso tiempo en hacerlo más fácil para él; y
  • ¡Nunca usar una función con nombres como «foo», «bar», o «Hazlo»!

Cómo Trabajar con Código Pobre

Es muy común tener que trabajar con código de pobre
calidad que alguien más ha escrito. Sin embargo, no pienses muy
pobremente de ellos, hasta que hayas caminado con sus zapatos. A ellos
se le pudo haber pedido muy conscientemente hacer algo rápidamente
para cumplir con la presión del calendario. Sin que esto importe, a
fin de trabajar con código poco claro debes comprenderlo. Comprenderlo
toma tiempo de aprendizaje, y ese tiempo tendrá que salir del
cronograma, de alguna parte, y debes insistir en ello. Para
comprenderlo, tendrás que leer el código fuente. Probablemente tendrás
que experimentar con él.

Este es un buen momento para documentar, incluso si es
solamente para ti mismo, debido a que el acto de intentar documentar
el código te forzará a considerar ángulos que podrías no haber
considerado, y el documento resultante puede ser útil. Mientras estás
haciendo esto, considera lo que tomaría reescribir alguna parte o todo
el código. ¿Realmente ahorraría tiempo reescribir parte de él?
¿Podrías confiar mejor en él si lo reescribes? Se cuidadoso aquí con
la arrogancia. Si lo reescribes, será más fácil para ti lidiar con él,
pero ¿realmente será más fácil para la próxima persona que tenga que
leerlo? Si lo reescribes, ¿cuál será la carga de la prueba?
¿Sobrepasará la necesidad de recomprobarlo cualquier beneficio que
pudiera ganarse?

En cualquier estimado que hagas para trabajar frente a
código que no escribiste, la calidad de ése código debería afectar tu
percepción del riesgo de problemas y los unk-unks.

Es importante recordar que la abstracción y la
encapsulación, dos de las mejores herramientas de un programador, son
particularmente aplicables al mal código. Puede que no seas capaz de
rediseñar un gran bloque de código, pero si puedes añadir cierta
cantidad de abstracción a él puedes obtener algunos de los beneficios
de un buen diseño sin reelaborar todo el desorden. En particular,
puedes intentar identificar las partes que son particularmente malas de
tal forma que puedan ser rediseñadas independientemente.

Cómo Usar el Control del Código Fuente

Los sistemas de control de código fuente te permiten
manejar proyectos efectivamente. Ellas son muy útiles para una persona
y esenciales para un grupo. Registran todos los cambios en versiones
diferentes de manera que nunca se pierde ningún código y puede
asignársele significado a los cambios. Uno puede crear y depurar
código desechable con confianza usando un sistema de control de
código, puesto que el código que modificas se mantiene cuidadosamente
separado del código oficial comprometido que será compartido con el
equipo o liberado.

Tardé en apreciar los beneficios de los sistemas de
control de código pero ahora no viviría sin uno aún en proyectos
personales. Generalmente son necesarios cuando tienes equipos
trabajando sobre el mismo código base. Sin embargo, tienen otra gran
ventaja: fomentan el pensar acerca del código como un sistema orgánico
en crecimiento. Puesto que cada cambio se etiqueta como una nueva
revisión con un nuevo nombre o número, uno empieza a ver el software
como series de mejoras visiblemente progresivas. Pienso que esto es
especialmente útil para los principiantes.

Una buena técnica para usar un sistema de control de
código es permanecer a pocos días de estar actualizado todo el tiempo.
El código que no puede ser finalizado en unos cuantos días se
Chequea, pero de una forma que queda inactivo y no será oficialmente
nombrado, y por lo tanto no creará problemas para nadie más. Cometer
un error que desacelere a tus compañeros de equipo es un serio error;
es a menudo un tabú.

Cómo Probar Unidades

La prueba de unidad, la prueba de una pieza individual
de funcionalidad codificada por el equipo que lo escribió, es una
parte de la codificación, no algo diferente de ella. Parte del diseño
del código es diseñar cómo será probado. Deberías poner por escrito un
plan de prueba, incluso si solamente es una oración. A veces la
prueba será simple: «¿Se ve bien este botón?» Algunas veces será
complejo: «¿Retornó este algoritmo de hermanamiento precisamente las
parejas correctas?»

Usa chequeo de afirmaciones y prueba los manejadores
cada vez que sea posible. Esto no solamente atrapa los bugs
anticipadamente, sino que es muy útil después sobre la marcha y te
permite eliminar misterios de los que de otra forma tendrías que
preocuparte.

Los desarrolladores de la Programación Extrema han
escrito extensivamente sobre probar unidades efectivamente; no puedo
hacer nada mejor que recomendar sus escritos.

Toma Descansos Cuando estés Confundido

Cuando estés confundido, toma un descanso. Algunas
veces medito por 15 minutos cuando estoy confundido y el problema
mágicamente se descifra cuando regreso a él. El sueño de una noche a
veces hace lo mismo a una escala mayor. Es posible que el cambiar
temporalmente a cualquier otra actividad pueda funcionar.

Cómo Reconocer Cuándo Ir a Casa

La programación de computadoras es una actividad que
es también una cultura. El hecho desafortunado es que no es una
cultura que valora mucho la salud mental o física. Tanto por razones
histórico/culturales (la necesidad de trabajar por la noche en
computadoras sin mucha carga de trabajo, por ejemplo) y debido a la
abrumadora presión de tiempo de mercadeo y la escasez de programadores,
los programadores de computadoras son tradicionalmente
sobretrabajados. No creo que puedas fiarte de todas las historias que
escuches, pero pienso que 60 horas a la semana es común, y 50 es un
mínimo muy común. Esto significa que a menudo se requiere mucho más
que eso. Este es un serio problema para un buen programador, el cual
es responsable no solamente por él mismo sino también por sus compañeros
de equipo. Tienes que reconocer cuándo ir a casa, y a veces cuándo
sugerir que otras personas vayan a casa. No puede haber ninguna regla
fija para resolver este problema, más de lo que puede haberla para
alzar un niño en brazos, por la misma razón—cada ser humano es
diferente.

Más allá de 60 horas a la semana es un extraordinario
esfuerzo para mí, el cual puedo aplicar por cortos periodos de tiempo
(cerca de una semana), y eso se espera de mí algunas veces. No sé si
es legal esperar 60 horas de trabajo de una persona; incluso no sé si
40 es legal. Estoy seguro, sin embargo, que es estúpido trabajar tanto
que te excedas de esas horas extras que trabajas. Personalmente para
mí, eso es más de las 60 horas a la semana. Personalmente pienso que
un programador debería ejercer su noble obligación y apoyar una carga
pesada. Sin embargo, no es el deber de un programador ser un patsy. El
hecho triste es que a los programadores a menudo se les pide
ser patsies es a fin de poner en escena a alguien, por ejemplo a un
administrador tratando de impresionar a un ejecutivo. Los
programadores a menudo sucumben a esto debido a que ellos son más
propensos a agradar y no muy buenos para decir no. Hay cuatro defensas
contra esto:

  • Comunícate tanto como sea posible con todos en la compañía de tal
    forma que nadie pueda extraviar a los ejecutivos acerca de lo que
    está pasando,
  • Aprende a estimar y calendariza defensiva y explícitamente y
    darle a todos la visibilidad de en qué consiste el calendario y dónde
    se encuentra,
  • Aprende a decir no, y di no como equipo cuando sea necesario, y
  • Renuncia si tienes que hacerlo.

La mayoría de los programadores son buenos
programadores, y los buenos programadores quieren lograr hacer un
montón de cosas. Para hacer eso, ellos tienen que administrar su
tiempo efectivamente. Hay una cierta cantidad de inercia mental
asociada con el entusiasmarse con un problema e involucrarse
profundamente con él. Muchos programadores encuentran que trabajan mejor
cuando tienen largos e ininterrumpidos bloques de tiempo en los
cuales entusiasmarse y concentrarse. Sin embargo, la gente debe dormir
y realizar otros deberes. Cada persona necesita encontrar una forma
de satisfacer tanto su ritmo humano como su ritmo de trabajo. Cada
programador necesita hacer lo que sea para procurar periodos de
trabajo eficiente, tales como reservar ciertos días en los cuales
atienda solamente las juntas más críticas.

Puesto que tengo niños, trato a veces de pasar las
tardes con ellos. El ritmo que funciona mejor para mí es trabajar un
muy largo día, dormir en la oficina o cerca de ella (hago un largo
viaje de mi casa al trabajo) luego voy a casa lo suficientemente
temprano al día siguiente para pasar tiempo con mis niños antes de que
se vayan a la cama. No estoy cómodo con esto, pero es el mejor
compromiso que he sido capaz de hacer. Ve a casa si tienes una
enfermedad contagiosa. Deberías ir a casa si estás teniendo
pensamientos suicidas. Deberías tomar un descanso o ir a casa si
tienes pensamientos homicidas por más de unos pocos segundos. Deberías
enviar a alguien a casa si ellos muestran mal funcionamiento mental o
signos de una enfermedad mental más allá de una leve depresión. Si
estás tentado a ser deshonesto o defraudante en una forma que
normalmente no eres debido a la fatiga, deberías tomarte un descanso.
No uses cocaína o anfetaminas para combatir la fatiga. No abuses de la
cafeína.

Cómo Lidiar con Gente Difícil

Probablemente tienes que lidiar con gente difícil. Tú
mismo incluso puedes ser una persona difícil. Si eres el tipo de
persona que tiene muchos conflictos con los compañeros de trabajo y
figuras de autoridad, deberías apreciar la independencia que eso
implica, pero trabaja en tus habilidades interpersonales sin
sacrificar tu inteligencia o principios.

Esto puede ser muy molesto para algunos programadores
que no tienen experiencia en este tipo de cosas y cuya experiencia de
vida precia les ha enseñado patrones de comportamiento que no son muy
útiles en el lugar de trabajo. La personas difíciles están a menudo
habituadas al desacuerdo y son menos afectadas por la presión social
para comprometerse que otras. La clave es respetarlos apropiadamente,
lo cual es más de lo que tu querrás hacer pero no es tanto como lo que
ellos podrían querer.

Los programadores tienen que trabajar juntos como un
equipo. Cuando surgen los desacuerdos, deben ser resueltos de algún
modo, no pueden ser esquivados por mucho tiempo. Las personas
difíciles son a menudo extremadamente inteligentes y tienen algo muy
útil que decir. Es crítico que escuches y entiendas a la persona
difícil sin prejuicios causados por ella. Un falla de comunicación es a
menudo la base del desacuerdo pero a veces puede ser eliminada con
gran paciencia. Intenta mantener esta comunicación fresca y cordial, y
no aceptes ninguna provocación para agrandar el conflicto que pueda
ofrecerse. Después de un razonable periodo para intentar comprender,
toma una decisión.

No permitas que la intimidación te fuerce a hacer algo
con lo que no estás de acuerdo. Si eres el líder, haz lo que piensas
que es mejor. No tomes una decisión por razones personales, y está
preparado para explicar las razones de tu decisión. Si eres compañero
de equipo con una persona difícil, no permitas que la decisión del
líder tenga ningún impacto personal. Si no es a tu modo, hazlo de la
otra forma de todo corazón.

La gente difícil cambia y mejora. Lo he visto con mis
propios ojos, pero es muy raro. Sin embargo, todos tienen altibajos
transitorios.

Uno de los desafíos que cada programador y
especialmente los líderes enfrentan es mantener a la persona difícil
completamente comprometida. Ellos son mucho más propensos a evadir
trabajo y resistir pasivamente que otros.

Capítulo 3. Intermedio

Tabla de Contenido

Habilidades Personales
Cómo Permanecer Motivado
Cómo ser Ampliamente Confiable
Cómo Negociar Tiempo vs. Espacio
Cómo Hacer Pruebas de Estrés
Cómo Balancear la Brevedad y la Abstracción
Cómo Aprender Nuevas Habilidades
Aprende a Teclear
Cómo Hacer Pruebas de Integración
Lenguajes de Comunicación
Herramientas Pesadas
Cómo Analizar Datos
Habilidades de Equipo
Cómo Administrar el Tiempo de Desarrollo
Cómo Manejar Riesgos de Software de Terceras Partes
Cómo Manejar Consultores
Cómo Comunicar la Cantidad Adecuada
Cómo Disentir Honestamente y Sobrellevarlo
Juicio
Cómo Negociar Calidad Frente a Tiempo de Desarrollo
Cómo Manejar la Dependencia del Sistema de Software
Cómo Decidir si el Software es Muy Inmaduro
Cómo Hacer una Decisión de Compra vs. Construcción
Cómo Crecer Profesionalmente
Cómo Evaluar Entrevistados
Cómo Saber Cuándo Aplicar Ciencia Computacional Fantasiosa
Cómo Hablar con No Ingenieros

Habilidades Personales

Cómo Permanecer Motivado

Es un hecho maravilloso y sorprendente que los
programadores son altamente motivados por el deseo de crear artefactos
que sean bellos, útiles, o nifty. Este deseo no es único para los
programadores ni universal pero es tan fuerte y común entre los
programadores que los separa de otros en otros roles.

Esto tiene consecuencias prácticas e importantes. Si a
los programadores se les pide hacer algo que no sea bello, útil, o
nifty, tendrán la moral baja. Hay un montón de dinero que ganar
haciendo material feo, estúpido y aburrido; pero al final, la
diversión hará la mayor cantidad de dinero para la compañía.

Obviamente, existen industrias completas organizadas
alrededor de técnicas motivacionales algunas de las cuales se aplican
aquí. Las cosas que son específicas a la programación que puedo
identificar son:

  • Usa el mejor lenguaje para el trabajo.
  • Busca oportunidades para aplicar nuevas técnicas, lenguajes, y tecnologías.
  • Intenta aprender o enseñar algo, aunque sea algo pequeño, en cada proyecto.

Finalmente, si es posible, mide el impacto de tu
trabajo en términos de algo que será personalmente motivador. Por
ejemplo, al corregir bugs, contar el número de bugs que he corregido
no es del todo motivacional para mí, debido a que es independiente del
número que puedan aún existir, y también afecta el valor total que
estoy agregando a los clientes de mi compañía de la más pequeña forma
posible. Relacionar cada bug con un cliente feliz, sin embargo, es personalmente motivador para mí.

Cómo ser Ampliamente Confiable

Para ser confiable debes ser confiable. Debes también
ser visible. Si nadie sabe acerca de ti, no se invertirá ninguna
confianza en ti. Con quienes están cerca de ti, tales como tus
compañeros de equipo, esto no debería ser un problema. Tú estableces
confianza siendo responsable e informativo para aquellos fuera de tu
departamento o equipo. Ocasionalmente alguien abusará de esta
confianza, y pedirá favores no razonables. No temas a esto, sólo explica
a lo que tendrías que renunciar al hacer el favor.

No pretendas saber algo que no sabes. Con la gente que
no son compañeros de equipo, puede que tengas que hacer una clara
distinción entre «no conocer bien el límite de mis capacidades» y «no
ser capaz de hacerlo, nunca.»

Cómo Negociar Tiempo vs. Espacio

Puedes ser un buen programador sin ir a la
universidad, pero no puedes ser un buen programador intermedio sin
conocer la teoría de la complejidad computacional básica. No necesitas
conocer la notación de la «gran O», pero personalmente pienso que
deberías ser capaz de comprender la diferencia entre «constantes de
tiempo», «n logaritmo de n» y «n al cuadrado». Podrías ser capaz de
intuir cómo negociar tiempo frente a espacio sin ese conocimiento, pero
en su ausencia no tendrás una base firme para comunicarte con tus
colegas.

Al diseñar o comprender de un algoritmo, la cantidad
de tiempo que toma para ejecutarse es a veces una función del tamaño
de la entrada. Cuando eso es cierto, podemos decir que el peor, el
mejor y el caso esperado de tiempo de ejecución de un algoritmo es «n
log n» si es proporcional al tamaño ($n$) veces el logaritmo del
tamaño. La notación y forma de hablar puede ser también aplicada al
espacio tomado por una estructura de datos.

Para mí, la teoría de la complejidad computacional es
bella y tan profunda como la física—¡y con poquito margen continúan
juntas por un largo trecho!

El tiempo (los ciclos del procesador) y el espacio (la
memoria) pueden ser negociados entre sí. La ingeniería trata acerca
de compromisos, y este es un buen ejemplo. No siempre es sistemática.
En general, sin embargo, uno puede ahorrar espacio al codificar las
cosas más fuertemente, al costo de más tiempo de computación cuando
tienes que decodificarlas. Puedes ahorrar tiempo mediante el cacheo, o
sea, al invertir espacio para almacenar una copia local de algo, al
costo de tener que mantener la consistencia del caché. Puedes a veces
ahorrar tiempo manteniendo más información en una estructura de datos.
Esto usualmente cuesta una pequeña cantidad de espacio pero puede
complicar el algoritmo.

Mejorar el intercambio espacio/tiempo puede a menudo
cambiar a uno o al otro dramáticamente. Sin embargo, antes de que
trabajes en esto deberías preguntarte a ti mismo si lo que estás
mejorando es realmente lo que necesita la mejoría. Es divertido
trabajar en un algoritmo, pero no puedes permitir que te ciegue hasta
el frío y duro hecho de que el mejorar algo que no es un problema no
hará ninguna notable diferencia y que sólo creará una carga de prueba.

La memoria en las modernas computadoras parece barata,
debido a que a diferencia del tiempo de procesador, no puedes verla
en uso hasta que golpeas la pared; pero entonces la falla es
catastrófica. Hay también otros costos ocultos al usar la memoria,
tales como su efecto en otros programas que deben ser residentes, y el
tiempo para asignarla y desasignarla. Considera esto cuidadosamente
antes de que sacrifiques espacio para ganar velocidad.

Cómo Hacer Pruebas de Estrés

Las pruebas de estrés son divertidas. Al principio
parece que el propósito de las pruebas de estrés es determinar si el
sistema trabaja bajo una carga. En realidad, es común que el sistema
no funcione bajo una carga pero falla de alguna manera cuando la carga
es lo suficientemente pesada. Llamo a esto I golpear la pared o bonking[1].
Pueden haber algunas excepciones, pero casi siempre hay una ‘pared’.
El propósito de las pruebas de estrés es determinar dónde está la
pared, y luego se deduzca cómo moverla un poco más allá.

Un plan para las pruebas de estrés debería
desarrollarse en la etapas tempranas del proyecto, debido a que a
menudo ayuda a clarificar exactamente lo que se espera. ¿Son dos
segundos para una solicitud de página web una falla miserable o un
éxito aplastante? ¿Son suficientes 500 usuarios concurrentes? Eso, por
supuesto, depende, pero uno debe saber la respuesta cuando se diseña el
sistema que conteste la pregunta. La prueba de estrés necesita
modelar la realidad lo suficientemente bien como para ser útil. No es
realmente posible simular muy fácilmente 500 erráticos e impredecibles
humanos usando un sistema concurrentemente, pero uno puede al menos
crear 500 simulaciones e intentar modelar alguna parte de lo que ellos
podrían hacer.

En las pruebas de estrés, empieza con una ligera carga
y carga el sistema a lo largo de alguna dimensión—tal como el tipo o
el tamaño de la entrada—hasta que golpees la pared. Si la pared
está demasiado cerca para satisfacer tus necesidades, resuelve cuál
recurso es el cuello de botella (usualmente hay uno que predomina.)
¿Es la memoria, el procesador, la E/S, el ancho de banda, o la
contención de datos? Luego determina cómo puedes mover la pared. Nota
que mover la pared, es decir, incrementar la carga máxima que el
sistema puede manejar, podría no ayudar o de hecho afectar el desempeño
de sistema ligeramente cargado. Usualmente el desempeño bajo carga
pesada es más importante que el desempeño bajo una carga ligera.

Puede que tengas que obtener visibilidad desde varias
dimensiones diferentes para construir un modelo mental de él; ninguna
técnica por sí sola es suficiente. Por ejemplo, hacer un registro de
sucesos a menudo da una buena idea del tiempo del reloj de pared entre
dos eventos en el sistema, pero a menos que sea cuidadosamente
construido, no proporciona visibilidad de la utilización de la memoria
e incluso del tamaño de la estructura de datos. De manera similar, en
un sistema moderno, pueden estar cooperando un número de computadoras y
muchos sistemas de software. Particularmente cuando estás golpeando
la pared (o sea, el desempeño es no lineal en el tamaño de la entrada)
esos otros sistemas de software pueden ser un cuello de botella. La
visibilidad en esos sistemas, aún si solamente mides la carga del
procesador en todas las máquinas participantes, puede ser muy útil.

Saber dónde está la pared es esencial no solamente
para moverla, sino también para proporcionar previsibilidad de tal
manera que el negocio pueda ser administrado efectivamente.

Cómo Balancear la Brevedad y la Abstracción

La abstracción es clave para la programación.
Deberías elegir cuidadosamente qué tan abstracto necesitas ser. Los
programadores principiantes en su entusiasmo a menudo crean más
abstracción de la que es realmente útil. Una señal de ello es si creas
clases que realmente no contienen ningún código y realmente no hagan
algo excepto servir para abstraer algo. La atracción de esto es
comprensible pero el valor de la brevedad del código puede ser medida
frente al valor de la abstracción. Ocasionalmente, uno observa un
error hecho por idealistas entusiastas: al inicio del proyecto se
definen un montón de clases que parecen maravillosamente abstractas y
uno puede especular que ellas manejarán cada eventualidad que pueda
surgir. A medida que el proyecto progresa y la fatiga empieza a
sentirse, el código mismo se vuelve desordenado. El cuerpo de las
funciones se vuelve más largo de lo que deberían ser. Las clases vacías
son una carga al documentar que es ignorada cuando se está bajo
presión. El resultado final habría sido mejor si la energía gastada en
la abstracción hubiese sido invertida en mantener las cosas pequeñas y
simples. Esta es una forma de programación especulativa. Recomiendo fuertemente el artículo «Succinctness is Power» (La Concisión es Poder) de Paul Graham [PGSite].

Hay un cierto dogma asociado con técnicas útiles tales como el ocultamiento de la información y la programación orientada a objetos
que a veces se llevan demasiado lejos. Esas técnicas le permiten a
uno codificar abstractamente y anticipar cambios. Personalmente pienso,
sin embargo, que no deberías producir mucho código especulativo. Por
ejemplo, es un estilo aceptado ocultar una variable entera en un
objeto tras mutators y accesorios, de tal manera que la variable misma
no esté expuesta, solamente la pequeña interface a ella. Esto permite
que la implementación de esa variable sea cambiada sin afectar al
código de llamada, y es quizá apropiado para un escritor de
bibliotecas que debe publicar una API (Application Program Interface,
Interfaz de Programa de aplicación) muy estable. Pero no creo que el
beneficio de esto supere el costo de la palabrería de ello cuando mi
equipo posee el código llamador y por lo tanto puede recodificar al
llamador tan fácilmente como al llamado. Cuatro o cinco líneas extra
de código es un pesado precio a pagar por este beneficio especulativo.

La portabilidad posee un problema similar. ¿Debería
el código ser portable a una computadora, compilador, sistema de
software o plataforma diferente, o simplemente ser fácilmente portado?
Pienso que una pieza de código no portable, pequeña y fácilmente
portada es mejor que una ampliamente portable. Es relativamente fácil y
ciertamente una buena idea confinar el código no portable a áreas no
designadas, tales como una clase que hace consultas a una base de
datos que son específicos para un DBMS (Data Base Management System)
dado.

Cómo Aprender Nuevas Habilidades

Aprender nuevas habilidades, especialmente las no
técnicas, es la diversión más grande de todas. La mayoría de las
compañías tendrían una mejor moral si comprendieran cuánto motiva esto
a los programadores.

Los humanos aprenden haciendo. La lectura de libros y
la toma de cursos son útiles. Pero ¿podrías tener algún respeto por un
programador que nunca ha escrito un programa? Para aprender cualquier
habilidad, tienes que ponerte a ti mismo en una posición dispensadora
donde puedas ejercitar esa habilidad. Cuando aprendas un nuevo
lenguaje de programación, trata de hacer un pequeño proyecto en él
antes de que tengas que hacer un proyecto grande. Cuando estés
aprendiendo a manejar un proyecto de software, trata de manejar
primero uno pequeño.

Un buen mentor no es reemplazo para hacer cosas por ti
mismo, pero es mucho mejor que un libro. ¿Qué puedes ofrecer a un
mentor potencial a cambio de su conocimiento? Como mínimo, deberías
ofrecer estudiar duro de tal manera que su tiempo no será
desperdiciado.

Intenta conseguir que tu jefe te permita tener
entrenamiento formal, pero comprende que ello a menudo no es mucho
mejor que la misma cantidad de tiempo invertida simplemente en jugar
con la nueva habilidad que deseas aprender. Es, sin embargo, más fácil
solicitar entrenamiento que tiempo para jugar en nuestro mundo
imperfecto, aunque es sabido que una gran parte del entrenamiento formal
consiste solamente en dormir a través de las conferencias esperando
la fiesta de la cena.

Si diriges personas, entiende cómo ellos aprenden y
apóyalos asignándoles proyectos que sean del tamaño adecuado y que
ejerciten habilidades en las que están interesados. No olvides que las
habilidades más importantes para un programador no son las técnicas.
Dale a tu gente una oportunidad para jugar y practicar coraje,
honestidad, y comunicación.

Aprende a Teclear

Aprende a teclear bien. Esta es una habilidad
intermedia debido a que escribir código es tan difícil que la
velocidad a la cual puedas teclear es irrelevante y no puedes hacer
mucho durante el tiempo que toma escribir código, no importa qué tan
bueno eres. Sin embargo, mientras seas un programador intermedio
probablemente pasarás mucho tiempo escribiendo lenguaje natural para
tus colegas y otros. Esta es una divertida prueba de tu compromiso;
requiere tiempo dedicado que no es muy divertido aprender algo como
eso. La leyenda dice que cuando Michael Tiemann [2]
estaba en el MCC la gente se quedaba fuera detrás de su puerta para
escuchar el zumbido generado por sus golpes de tecla los cuales eran
tan rápidos como indistinguibles.

Cómo Hacer Pruebas de Integración

La prueba de integración es la prueba de la
integración de varios componentes que han sido probados como unidades
independientes. La integración es costosa y el costo proviene de la
prueba. Debes incluir tiempo para esto en tus estimados y tu
cronograma.

Idealmente deberías organizar un proyecto de tal forma
que no sea una fase al final donde la integración debe explícitamente
tomar lugar. Es mucho mejor integrar gradualmente las cosas a medida
que se completan en el curso del proyecto. Si es inevitable estímalo
cuidadosamente.

Lenguajes de Comunicación

Hay algunos lenguajes, es decir, sistemas sintácticos formalmente definidos, que no son lenguajes de programación sino lenguajes de comunicación—son
diseñados específicamente para facilitar la comunicación a través de
la estandarización. En el 2003 los más importantes fueron el UML, el
XML, y el SQL. Deberías tener alguna familiaridad con todos ellos de
manera que puedas comunicarte bien y decidir cuándo usarlos.

El UML es un rico sistema formal para hacer diagramas
que describen diseños. Su belleza descansa en que es tanto visual como
formal, capaz de transmitir una gran cantidad de información si tanto
el autor como la audiencia conocen el UML. Necesitas saber sobre él
debido a que los diseños están algunas veces comunicados en él. Hay
muchas herramientas útiles para hacer diagramas UML que lucen muy
profesionales. En muchos casos el UML es demasiado formal, y me
descubro a mí mismo usando un estilo más simple de cajas y flechas para diseñar diagramas. Pero estoy muy seguro que el UML es al menos tan bueno para ti como el estudiar Latín.

El XML es un estándar para diseñar nuevos estándares. No
es una solución para problemas de intercambio de datos, aunque
algunas veces lo veas presentado como si lo fuera. Más bien, es una
bienvenida automatización de las más aburridas partes del intercambio
de datos, como es, el estructurar la representación en una secuencia
lineal y analizar la estructura. Provee un agradable chequeo de tipos
-y de correctitud-, aunque de nuevo es solamente una fracción de lo
que probablemente vas a necesitar en la práctica.

El SQL es un muy poderoso y rico lenguaje de
manipulación de datos que no es propiamente un lenguaje de
programación. Tiene muchas variantes, típicamente muy dependientes del
producto, las cuales son menos importantes que el núcleo
estandarizado. El SQL es la lingua franca de las bases de datos
relacionales. Puede que trabajes o no en cualquier campo que pueda
beneficiarse de una comprensión de las bases de datos relacionales,
pero deberías tener una comprensión básica de ellas y de la sintaxis y
significado del SQL.

Herramientas Pesadas

A medida que nuestra cultura tecnológica progresa, la
tecnología del software se mueve de lo inconcebible, a la
investigación, a nuevos productos, a productos estandarizados, a
productos ampliamente disponibles y baratos. Esas herramientas pesadas
pueden sobrellevar grandes cargas, pero pueden ser intimidantes y
requieren una gran inversión en su comprensión. El programador
intermedio tiene que saber cómo manejarlas y cuándo deberían ser
usadas o consideradas.

A mi entender algunas de las mejores herramientas son:

  • Bases de Datos Relacionales,
  • Motores de Búsqueda de Texto Completo,
  • Bibliotecas Matemáticas,
  • OpenGL,
  • parsers XML, y
  • Hojas de Cálculo.

Cómo Analizar Datos

El análisis de datos es un proceso en las primeras
etapas del desarrollo de software, cuando examinas una actividad de
negocio y encuentras los requerimientos para convertirlo en una
aplicación de software. Esta es una definición formal, la cual puede
conducir a pensar el análisis de datos es una acción que deberías
dejar mejor a los analistas de sistemas, mientras tú, el programador,
deberías enfocarte en codificar lo que alguien más ha diseñado. Si
seguimos estrictamente el paradigma de la ingeniería de software, ello
podría ser correcto. Los programadores experimentados se vuelven
diseñadores y los más agudos diseñadores se convierten en analistas de
negocios, siendo así intitulados a pensar en todos los requerimientos
de datos y a darte tareas bien definidas para hacer. Esto no es
completamente exacto, debido a que los datos son el núcleo de cada
actividad de la programación. Lo que sea que hagas en tus programas,
estás moviéndote alrededor de o modificando los datos. El analista de
negocios está analizando las necesidades a una mayor escala, y el
diseñador de software está exprimiendo más dicha escala de tal forma
que, cuando el problema aterriza en tu escritorio, parece que todo lo
que necesitas hacer es aplicar algoritmos inteligentes y comenzar a
mover los datos existentes.

No es así.

No importa en cuál etapa empieces a verlo, los datos
son el principal interés de una aplicación bien diseñada. Si miras de
cerca cómo un analista de negocios obtiene los requirimientos de la
solicitud del cliente, te darás cuenta de que los datos juegan un
papel fundamental. El analista crea los llamados Diagramas de Flujo de
Datos, donde todos las fuentes de datos están identificadas y el
flujo de la información es modelada. Habiendo definido claramente cuáles
datos deberían formar parte del sistema, el diseñador modela las
fuentes de datos, en términos de relaciones de bases de datos,
protocolos de intercambio de datos, y formatos de archivos, de tal
manera que la tarea está lista para ser pasada al programador. Sin
embargo, el proceso no termina todavía, porque tú «el programador» aún
después de este completo proceso de refinamiento de datos, se te pide
analizar los datos para llevar a cabo la tarea de la mejor forma
posible. La línea final de tu tarea es el mensaje central de Niklaus
Wirth, el padre de varios lenguajes. «Algoritmos + Estructuras de
Datos = Programas» Nunca ha habido un algoritmo que permanezca solo,
haciendo algo para él mismo. Cada algoritmo está supuesto a hacer algo
para al menos una pieza de datos.

Por lo tanto, puesto que los algoritmos no atan sus
ruedas al vacío, necesitas analizar tanto los datos que alguien más ha
identificado para ti como los datos que son necesarios para escribir
tu código. Un ejemplo trivial hará la cuestión más clara. Estás
implementando una rutina de búsqueda para una biblioteca. De acuerdo a
tus especificaciones, el usuario puede seleccionar libros mediante la
combinación de género, autor, título, editor, año de impresión, y
número de páginas. La meta última de tu rutina es producir una
sentencia SQL legal para buscar la base de datos subyacente. Basado en
esos requerimientos, tienes varias opciones: chequear cada control por
turnos, usar una sentencia «switch», o varios «ifs»; hacer un arreglo
de controles de datos, chequear cada elemento para ver si está
establecido; crear (o usar) un objeto de control abstracto desde el
cual heredar todos tus controles específicos, y conectarlos a un motor
conducido por eventos. Si tus requerimientos incluyen también
optimizar el desempeño de la consulta, asegurándote que los ítems sean
Chequeados en un orden específico, puedes considerar el uso de un árbol
de componentes para construir tu sentencia SQL. Como puedes ver, la
elección del algoritmo depende de los datos que decidas usar, o crear.
Tales decisiones pueden hacer toda la diferencia entre un algoritmo
eficiente y uno desastroso. Sin embargo, la eficiencia no es la única
preocupación. Puedes usar una docena de variables en tu código y
hacerlo tan eficiente como podría serlo. Pero tal pieza de código
podría no ser fácilmente mantenible. Quizá el elegir un contenedor
apropiado para tus variables podría mantener la misma velocidad y
adicionalmente permitir a tus colegas comprender mejor el código cuando
lo vean el próximo año. Además, el escoger una estructura de datos
bien definida puede permitirles extender la funcionalidad de tu código
sin reescribirlo. A la larga, tus escogencias de datos determinan qué
tanto sobrevivirá tu código después de que lo finalices. Permíteme
darte otro ejemplo, solamente algo más en lo que pensar. Supongamos
que tu tarea es encontrar todas las palabras en un diccionario con más
de tres anagramas, donde un anagrama debe ser otra palabra del mismo
diccionario. Si piensas en ello como una tarea computacional,
terminarás con un esfuerzo sin fin, intentando trabajar todas las
combinaciones de cada palabra y luego comparándola a las otras de la
lista. Sin embargo, si analizas los datos a mano, te darás cuenta de
que cada palabra puede ser representada por un registro conteniendo la
palabra en él mismo y un arreglo ordenado de sus letras como ID.
Armado con tal conocimiento, encontrar anagramas significa tan solo
ordenar la lista sobre el campo adicional y seleccionar las que
comparten el mismo ID. El algoritmo de fuerza bruta puede tomar varios
días para ejecutarse, mientras que el inteligente solo es cuestión de
unos pocos segundos. Recuerda este ejemplo la próxima vez que estés
encarando un problema intratable.

Habilidades de Equipo

Cómo Administrar el Tiempo de Desarrollo

Al administrar el tiempo de desarrollo, mantén un plan
del proyecto conciso y actualizado. Un plan del proyecto es un
estimado, un calendario, un conjunto de hitos (marcas que reflejen
avances) para marcar el progreso, y una asignación del tiempo de tu
equipo o de tu propio tiempo para cada tarea en el estimado. Debería
incluir también las cosas que tengas que recordar hacer, tales como
reunirte con la gente de aseguramiento de la calidad, preparar la
documentación, u ordenar hardware. Si estás en un equipo, el plan del
proyecto debería ser un acuerdo consensual, tanto al inicio como
mientras avanzas.

El plan del proyecto existe para ayudar a hacer
decisiones, no para mostrar qué tan organizado eres. Si el plan del
proyecto es demasiado largo o no está actualizado, será inútil para
hacer decisiones. En realidad, esas decisiones son sobre personas
individuales. El plan y tu juicio te permiten decidir si deberías
transferir tareas de una persona a otra. Los hitos marcan tu progreso.
Si usas una herramienta fantástica de planeación de proyecto, no te
dejes seducir para crear un Gran Diseño Desde el Frente (GDDF) para el
proyecto, pero úsala para mantener la concisión y la actualidad.

Si fallas un hito, deberías tomar una acción inmediata
tal como informar a tu jefe que la finalización programada de ese
proyecto se ha corrido por esa cantidad. El estimado y el cronograma
nunca podrían haber sido perfectos para comenzar; esto crea la ilusión
de que podrías ser capaz de reponer los días que perdiste en la
última parte del proyecto. Podrías. Pero es tan probable que hayas
subestimado esa parte como que la hayas sobrestimado. Por lo tanto la
finalización programada del proyecto ya se ha corrido, te guste o no.

Asegúrate que tu plan incluye tiempo para: reuniones
internas de equipo, demos, documentación, actividades periódicas
programadas, pruebas de integración, lidiar con foráneos,
enfermedades, vacaciones, mantenimiento de productos existentes, y
mantenimiento del ambiente de desarrollo. El plan del proyecto puede
servir como una vía para de dar a los foráneos o a tu jefe una visión a
lo interno de lo que tú o tu equipo están haciendo. Por esa razón
debería ser corto y actualizado.

Cómo Manejar Riesgos de Software de Terceras Partes

Un proyecto a menudo depende del software producido
por organizaciones que él no controla. Hay grandes riesgos asociados
con software de terceras partes que deberían ser reconocidos por todos
los involucrados.

Nunca, nunca, deposites ninguna esperanza en el vaporware. El vaporware
es cualquier software alegado que ha sido prometido pero que no está
disponible aún. Esta es la forma más segura de salir de los negocios. No
es sabio estar solamente escéptico de la promesa de una compañía de
software para liberar un cierto producto con una cierta funcionalidad
en una cierta fecha; es mucho más sabio ignorarlo completamente y
olvidar que alguna vez lo escuchaste. Nunca permitas que se incluya en
ningún documento usado por tu compañía.

Si el software de terceros no es vaporware, aún es
riesgoso, pero al menos es un riesgo que puede ser abordado. Si estás
considerando usar software de terceros, deberías dedicar energía
inicialmente a evaluarlo. A la gente podría no gustarle el escuchar
que tomará dos semanas o dos meses evaluar cada uno de los tres
productos por la conveniencia, pero tiene que hacerse tan pronto como
sea posible. El costo de integrar no puede ser exactamente estimado sin
una apropiada evaluación.

Comprender la conveniencia de software de terceras
partes para un propósito particular es conocimiento muy tribal. Es muy
subjetivo y generalmente radica en los expertos. Puede ahorrarte
mucho tiempo si puedes hallar esos expertos. A menudo muchas veces un
proyecto dependerá de un sistema de software de una tercera parte de
una forma tan completa que si la integración falla el proyecto
fallará. Expresa los riesgos como ése claramente al incluirlos en el
cronograma. Trata de tener un plan de contingencia, tal como otro
sistema que pueda ser usado o la capacidad de escribir la
funcionalidad tú mismo si el riesgo no puede ser removido antes. Nunca
dejes que un cronograma dependa del vaporware.

Cómo Manejar Consultores

Usa consultores, pero no confíes en ellos. Son gente
maravillosa y merecen una gran cantidad de respeto. Puesto que tienen
que ver muchos proyectos diferentes, a menudo saben más sobre
tecnologías específicas e incluso de técnicas de programación de lo
que tu sabrás. La mejor manera de usarlos es como educadores a
domicilio que puedan enseñar mediante el ejemplo.

Sin embargo, usualmente no pueden volverse parte del
equipo en el mismo sentido que lo son los empleados regulares, aunque
sea solo porque no puedes tener el tiempo suficiente como para conocer
sus fortalezas y sus debilidades. Su compromiso financiero es mucho
menor. Pueden moverse más fácilmente. Pueden tener menos que ganar si
la compañía lo hace bien. Algunos serán buenos, algunos promedio, y
algunos serán malos, pero es de esperar tu selección de consultores no
será tan cuidadosa como tu selección de empleados, de tal forma que
obtendrás más malos.

Si lo consultores van a escribir código, debes
revisarlo cuidadosamente a medida que avanzas. No puedes llegar al
final de un proyecto con el riesgo de un gran bloque de código que no
ha sido revisado. Esto es cierto para todos los miembros del equipo,
en realidad, pero usualmente tendrás más conocimiento de los miembros
del equipo más cercanos a ti.

Cómo Comunicar la Cantidad Adecuada

Considera cuidadosamente el costo de una junta; cuesta su duración multiplicada por el número de participantes.
Las juntas son algunas veces necesarias, pero las más pequeñas son
usualmente las mejores. La calidad de la comunicación en pequeñas
juntas es mejor, y el total de tiempo desperdiciado es menor. Si
alguna persona está aburrida en la junta toma eso como una señal, que
la junta debería ser más pequeña.

Debería hacerse todo lo posible para fomentar la
comunicación informal. El trabajo más útil se realiza durante los
almuerzos con colegas que durante cualquier otro tiempo. Es una
lástima que la mayoría de las compañías no reconozcan ni apoyen este
hecho.

Cómo Disentir Honestamente y Sobrellevarlo

El desacuerdo es una gran oportunidad para hacer una
buena decisión, pero debería ser manejada con delicadeza. Con mucha
esperanza sientes que has expresado tu opinión adecuadamente y han
sido escuchadas antes de que la decisión sea hecha. En ese caso no hay
nada más que decir, y deberías decidir si aceptarás la decisión
aunque no concuerdes con ella. Si puedes apoya esta decisión aunque no
concuerdes con ella, dilo así. Eso demuestra cuán valioso eres porque
eres independiente y no eres un hombre «sí señor», sino respetuoso de
la decisión y un jugador de equipo.

A veces una decisión con la que no concuerdas será
hecha cuando los tomadores de decisión no tuvieron el total beneficio
de tu opinión. Deberías entonces evaluar si debes replantear el asunto
sobre las bases del beneficio para la compañía o para la tribu. Si en
tu opinión es un pequeño error, podría no valer la pena reconsiderar.
Si en tu opinión es una gran error, entonces por supuesto debes
presentar un argumento.

Usualmente, esto no es un problema. En algunas
circunstancias estresantes con algunos tipos de personalidad esto
puede conducir a que las cosas sean tomadas personalmente. Por
ejemplo, algunos muy buenos programadores carecen de la confianza
necesaria para desafiar una decisión aún cuando tienen buenas razones
para creer que es errada. En la peor de las circunstancias el tomador de
decisiones está inseguro y lo toma como un desafío personal a su
autoridad. Es mejor recordar que en tales circunstancias la gente
reacciona con la parte reptílea de sus cerebros. Deberías presentar tu
argumento en privado, e intentar mostrar cómo el nuevo conocimiento
cambia las bases sobre las cuales se tomó la decisión.

Sin importar si la decisión se revierta o no, debes
recordar que tu nunca deberás decir ‘¡Te lo dije!’ puesto que la
decisión alternativa fue completamente explorada.

Juicio

Cómo Negociar Calidad Frente a Tiempo de Desarrollo

El desarrollo de software es siempre un compromiso
entre lo que el proyecto hace y conseguir el proyecto hecho. Pero
puede que se te pida bajar el nivel de calidad a fin de acelerar la
implantación de un proyecto en una forma que ofenda tu sensibilidades
ingenieriles o de negocios. Por ejemplo, puede que se te pida hacer
algo que sea una práctica pobre de ingeniería de software y que
conducirá a un montón de problemas de mantenimiento.

Si esto sucede tu primer responsabilidad es informar a
tu equipo y claramente explicar el costo de la disminución de la
calidad. Después de todo, tu comprensión de ello debería ser mucho
mejor que la comprensión de tu jefe. Aclara lo que se está perdiendo y
lo que se está ganando, y a qué costo el terreno perdido será
recobrado en el próximo ciclo. En esto, la visibilidad proporcionada
por un buen plan de proyecto debería ser útil. Si el trueque de la
calidad por otra cosa afecta el esfuerzo de aseguramiento de la calidad,
señala eso (tanto a tu jefe como a la gente de aseguramiento de la
calidad). Si el trueque de calidad conducirá a que se reporten más
bugs después del periodo de aseguramiento de la calidad, señala eso
también.

Si él o ella insiste deberías intentar aislar la mala
calidad en componentes individuales que puedas planear reescribir o
mejorar en el próximo ciclo. Explica esto a tu equipo para que así
puedan planearlo.

NinjaProgrammer en Slashdot envió esta gema:

Recuerda que un buen diseño será
flexible frente a implementaciones de código pobre. Si existen buenas
interfaces y abstracciones a través del código, entonces las
reescrituras eventuales serán mucho menos dolorosas. Si es difícil
escribir código claro que sea difícil de corregir, considera lo que
está errado con el núcleo del diseño que está causando esto.

Cómo Manejar la Dependencia del Sistema de Software

Los sistemas modernos de software tienden a depender
de un gran número de componentes que pueden no estar directamente bajo
tu control. Esto incrementa la productividad a través de la sinergía y
la reutilización. Sin embargo, cada componente trae consigo algunos
problemas:

  • ¿Cómo corregirás los bugs en el componente?
  • ¿Te restringe el componente a sistemas de hardware o software particulares?
  • ¿Qué harás si el componente falla completamente?

Siempre es mejor encapsular el componente de alguna
manera de tal forma que esté aislado y de tal manera que pueda ser
reemplazado. Si el componente prueba ser completamente inoperable,
puede que tengas que conseguir uno diferente, pero puede que tengas
que escribir el tuyo propio. La encapsulación no es portabilidad, pero
la hace más fácil, lo cual es casi tan bueno.

Tener el código fuente de un componente decrementa el
riesgo por un factor de cuatro. Con el código fuente, puedes evaluarlo
más fácilmente, depurarlo más fácilmente, hallar formas de corregir
los problemas más fácilmente, y hacer correcciones más fácilmente. Si
haces correcciones , deberías dárselas al propietario del componente y
obtener las correcciones incorporadas en una versión oficial; de otro
modo tendrás que mantener incómodamente una versión no oficial.

Cómo Decidir si el Software es Muy Inmaduro

Usar el software que otra persona escribió es uno de
las más efectivas formas de construir rápidamente un sistema sólido.
Debería no ser desalentado, pero los riesgos asociados con ello deben
ser examinados. Uno de los más grandes riesgos es el periodo de
bugginess y la cercana inoperabilidad que a menudo está asociada con
el software antes de que madure, a través del uso, en un producto
utilizable. Antes de que consideres integrar con un sistema de software,
sin importar si se creó en casa o por una tercera parte, es muy
importante considerar si en realidad es lo suficientemente maduro para
ser usado. Aquí están diez preguntas que deberías hacerte a ti mismo
al respecto:

  1. ¿Es vaporware? (Las promesas son muy inmaduras).
  2. ¿Hay un cuerpo de ciencia accesible acerca del software?
  3. ¿Eres el primer usuario?
  4. ¿Hay un fuerte incentivo para su continuación?
  5. ¿Ha tenido un esfuerzo de mantenimiento?
  6. ¿Sobrevirá la deserción de los actuales mantenedores?
  7. ¿Hay una alternativa madura al menos la mitad de buena?
  8. ¿Es conocido para tu tribu o compañía?
  9. ¿Es deseable para tu tribu o compañía?
  10. ¿Puedes contratar gente para trabajar en él aún si es malo?

Un poco de consideración sobre esos criterios
demuestran el gran valor del software libre bien establecido y del
software de fuente abierta al reducir riesgos para el emprendedor.

Cómo Hacer una Decisión de Compra vs. Construcción

Una compañía emprendedora o proyecto emprendedor que
está intentando hacer algo con software tiene que hacer constantemente
las llamadas decisiones de compra vs. construcción. Este juego
de palabras es desafortunado por dos cosas: parece ignorar el
software de fuente abierta y el software libre el cual no es
necesariamente comprado. Aún más importante, debería quizá ser llamado una decisión de obtener e integrar vs. construir aquí e integrar
debido a que el costo de la integración debe ser considerado. Esto
requiere una gran combinación de negocios, administración, y engineering
savvy.

  • ¿Qué tan bien satisface las necesidades para las cuales fue diseñado?
  • ¿Qué porción de lo que compres necesitarás?
  • ¿Cuál es el costo de evaluar la integración?
  • ¿Cuál es el costo de la integración?
  • ¿Comprar incrementará o decrementará a largo plazo los costos de mantenimiento?
  • ¿Construirlo te pondrá en una posición de negocios en la que no quieres estar?

Deberías pensar dos veces antes de construir algo que
sea lo suficientemente grande como para servir de base para otro
negocio completo. Tales ideas son a menudo propuestas por gente
brillante y optimista que tendrá mucho que contribuir a tu equipo. Si
su idea es obligatoria, puede que desees cambiar tu plan de negocios;
pero no investigues una solución más grande que tu propio negocio sin
un análisis consciente.

Después de considerar esas preguntas, deberías quizá
preparar dos borradores de planes de proyecto, uno para construir y
otro para comprar. Eso te forzará a considerar los costos de
integración. Deberías también considerar los costos de mantenimiento a
largo plazo de ambas soluciones. Para estimar los costos de
integración, tendrás que hacer una evaluación completa del software
antes de que lo compres. Si no puedes evaluarlo, asumirás un riesgo
irrazonable al comprarlo y deberías decidir contra comprar ese
producto particular. Si hay varias decisiones de compra bajo
consideración, tendrá que invertirse alguna energía en evaluar cada
una de ellas.

Cómo Crecer Profesionalmente

Asume responsabilidad encima de tu autoridad. Juega el
rol que deseas. Expresa aprecio por la contribución de la gente para
el éxito de la organización, al igual que a las cosas como las que te
ayudan personalmente.

Si quieres convertirte en un líder de equipo, instiga
la formación de consenso. Si quieres convertirte en un administrador,
toma responsabilidad por el cronograma. Usualmente puedes hacer esto
cómodamente mientras trabajas con un líder o un administrador, puesto
que ello les libera de tomar una responsabilidad más grande. Si eso es
demasiado para probar, hazlo un poco a la vez.

Evalúate tu mismo. Si quieres convertirte en un mejor
programador, pregúntale a alguien que admiras cómo puedes convertirte
en alguien como él. Puedes también preguntarle a tu jefe, quien sabrá
menos pero tendrá un impacto más grande sobre tu carrera.

Planea formas de aprender nuevas habilidades, tanto
del tipo trivial técnico, como aprender un nuevo sistema de software, y
el tipo trivial difícil, como escribir bien, integrándolas en tu
trabajo.

Cómo Evaluar Entrevistados

A la evaluación de empleados potenciales no se le da
la energía que merece. Una mala contratación, como un mal matrimonio,
es terrible. Una porción significativa de la energía de todos debería
dedicarse al reclutamiento, aunque esto se hace raramente.

Hay diferentes estilos de entrevista. Algunas son
tortuosas, diseñadas para poner al candidato bajo una gran carga de
estrés. Esto sirve al muy valioso propósito de revelar posiblemente
las fallas de carácter y las debilidades bajo estrés. Los candidatos
no son más honestos con los entrevistadores de lo que lo son con ellos
mismos, y la capacidad humana para auto decepción es asombrosa.

Deberías, como mínimo, dar al candidato el equivalente
de un examen oral sobre las habilidades técnicas por dos horas. Con
práctica, serás capaz de cubrir rápidamente lo que ellos saben y
rápidamente retractarse de lo que no saben para marcar la frontera.
Los entrevistados respetarán esto. He escuchado varias veces a
entrevistados que dicen que la calidad del examen fue una de sus
motivaciones para escoger una compañía. La gente buena quiere ser
contratada por sus habilidades, no por dónde trabajaron por última vez
o a qué escuela fueron o algunas características no esenciales.

Al hacer esto, deberías también evaluar su capacidad
para aprender, la cual es mucho más importante de lo que ello saben.
Deberías también observar las bocanadas de azufre que da la gente
difícil. Puedes ser capaz de reconocerlo al comparar notas después de
la entrevista, pero al calor de la entrevista es difícil reconocer.
Qué tan bien se comunica la gente y trabaja con la gente es más
importante que estar capacitado en el último de los lenguajes de
programación.

Un lector ha tenido buena suerte usando una prueba
‘para llevar a casa’ para los entrevistados. Esto tiene la ventaja de
que puede descubrir a los entrevistados que pueden presentarse bien a
sí mismos pero que no pueden realmente codificar—y hay mucha gente
como esa. Personalmente no he probado esta técnica, pero suena
sensible.

Finalmente, entrevistar es también un proceso de
venta. Deberías estar vendiendo tu compañía o proyecto al candidato.
Sin embargo, estás hablando con un programador, así que no trates de
colorear la verdad. Empieza con lo malo, luego finaliza fuerte con lo
bueno.

Cómo Saber Cuándo Aplicar Ciencia Computacional Fantasiosa

Hay una base de conocimientos sobre algoritmos,
estructuras de datos, matemáticas, y otras carajos tópicos sobre la
que la mayoría de los programadores saben pero que raramente usan. En
la práctica, este maravilloso material es muy complicado y
generalmente innecesario. No hay punto en mejorar un algoritmo cuando
la mayoría de tu tiempo se invierte en hacer ineficientes llamadas a
bases de datos, por ejemplo. Una cantidad desafortunada de
programación consiste en obtener sistemas para hablar a cada uno de los
otros y usar estructuras de datos muy simples para construir una
interface de usuario agradable.

¿Cuándo es la alta tecnología la tecnología apropiada?
¿Cuándo deberías abrir un libro para obtener algo distinto a un
algoritmo de batalla? A veces es útil hacer esto pero debería ser
evaluado cuidadosamente.

Las tres consideraciones más importantes para la técnica de la ciencia computacional potencial son:

  • ¿Está bien encapsulado de tal manera que el riesgo para otros
    sistemas es bajo y el incremento general en complejidad y costo de
    mantenimiento es bajo?
  • ¿Es el beneficio sorprendente (por ejemplo, un factor de dos en un sistema maduro o un factor de diez en un nuevo sistema)?
  • ¿Serás capaz de probarlo y evaluarlo efectivamente?

Si un algoritmo bien aislado que usa un algoritmo
ligeramente fantasioso puede decrementar el costo del hardware o
incrementar el desempeño por un factor de dos a través de un sistema
completo, entonces sería criminal no considerarlo. Una de las claves
para argumentar por tal aproximación es mostrar que el riesgo es
realmente muy bajo, puesto que la tecnología propuesta ha sido
probablemente bien estudiada, el único punto importante es el riesgo
de la integración. Aquí la experiencia y el juicio de un programador
pueden verdaderamente sinergizarse con la tecnología fantasiosa para
hacer la integración fácil.

Cómo Hablar con No Ingenieros

Los ingenieros y los programadores en particular son
generalmente reconocidos por la cultura popular por ser diferentes de
las otras personas. Esto implica que las otras personas son diferentes
de nosotros. Vale la pena tener esto en mente cuando te comuniques
con no ingenieros; deberías siempre comprender a la audiencia.

Los no ingenieros son inteligentes, pero no son tan
aterrizados en crear cosas técnicas como nosotros. Nosotros hacemos
cosas. Ellos venden cosas y manejan cosas y cuentan cosas y
administran cosas, pero no son expertos en hacer cosas. Ello no son
tan buenos en el trabajo en equipos como los son los ingenieros (sin
duda hay excepciones.)[3]
Sus habilidades sociales son generalmente tan buenas o mejores que la
de los ingenieros en ambientes donde no hay equipos, pero su trabajo
no siempre demanda que practiquen el tipo de intimidad, comunicación
precisa y las cuidadosas subdivisiones de tareas que nosotros hacemos.

Los no ingenieros pueden ser demasiado dados a agradar
y pueden ser intimidados por ti. Al igual que nosotros, ellos pueden
decir ‘si’ sin realmente querer decirlo a fin de agradarte o porque
están un poco asustados por tu causa, y luego no respaldar su palabra.

Los no programadores pueden comprender cosas técnicas
pero no tienen lo que incluso es difícil para nosotros —el juicio
técnico. Ellos comprenden cómo funciona la tecnología, pero no pueden
entender por qué cierto acercamiento tomaría tres meses y otro tres
días. (Después de todo, los programadores son también anecdóticamente
horribles en este tipo de estimación.) Esto representa una gran
oportunidad para sinergizarse con ellos.

Cuando le hablas a tu equipo usarás, sin pensarlo, una
suerte de taquigrafía, un lenguaje abreviado que es efectivo debido a
que tendrás mucha experiencia compartida sobre la tecnología en
general y tu producto en particular. Requiere algo de esfuerzo no usar
este vocabulario con los que no tienen esa experiencia compartida,
especialmente cuando los miembros de tu equipo están presentes. Este
vocabulario crea una pared entre tú y los que no la comparten, y, peor
aún, desperdicia su tiempo.

Con tu equipo, las suposiciones básicas y metas no
necesitan ser restablecidas a menudo, y la mayoría de la conversación
se enfoca en los detalles. Con los foráneos, debe ser del otro modo.
Ellos pueden no comprender cosas que das por entendidas. Puesto que
las das por entendidas y no las repites, puedes dejar una conversación
con un foráneo pensando que comprendiste a los demás cuando realmente
hay una gran incomprensión. Deberías asumir que te comunicarás mal y
vigilar cuidadosamente para encontrar esta mala comunicación. Intenta
resumirlas o parafrasear lo que estás diciendo para asegurarte de que
comprenden. Si tienes la oportunidad de reunirte con ellos a menudo,
invierte un poco de tiempo preguntando si te estás comunicando
efectivamente, y cómo puedes hacerlo mejor. Si hay un problema en la
comunicación, busca alterar tus propias prácticas antes de frustrarte
con las suyas.

Adoro trabajar con no ingenieros. Proporciona grandes
oportunidades para aprender y enseñar. A menudo puedes guiar mediante
el ejemplo, en términos de la claridad de tu comunicación. Los
ingenieros están entrenados para poner orden al caos, para traer
claridad a la confusión, y a los no ingenieros les agrada eso de
nosotros. Debido a que tenemos juicio técnico y usualmente podemos
comprender tópicos de negocios, a menudo podemos encontrar una
solución simple a un problema.

A menudo los no ingenieros proponen soluciones que
piensan nos facilitarán las cosas sin bondades y por un deseo de hacer
lo correcto, cuando de hecho existe una solución general mucho mejor
la cual solamente puede verse sinergizando las visiones de los
foráneos con tu juicio técnico. Personalmente me gusta la Programación
Extrema porque resuelve esta ineficiencia; casando la estimación
rápidamente a la idea, hace más fácil hallar la idea que sea la mejor
combinación de costo y beneficio.


[1] “to hit”

Capítulo 4. Avanzado

Tabla de Contenido

Juicio Tecnológico
Cómo Diferenciar lo Difícil de lo Imposible
Cómo Utilizar Lenguajes Embebidos
Escogiendo Lenguajes
Comprometiéndote Sabiamente
Cómo Combatir Presión de Calendario
Cómo Comprender al Usuario
Cómo Obtener una Promoción
Sirviendo a Tu Equipo
Cómo Desarrollar Talento
Cómo Elegir Sobre Qué Trabajar
Cómo Obtener lo Máximo de Tus Compañeros de Equipo
Cómo Dividir Problemas
Cómo Manejar las Tareas Aburridas
Cómo Conseguir Apoyo para un Proyecto
Cómo Hacer Crecer un Sistema
Cómo Comunicar Bien
Cómo Decirle a la Gente Cosas que No Desean Escuchar
Cómo Lidiar con Mitos Administrativos
Cómo Lidiar con el Caos Organizacional

Juicio Tecnológico

Cómo Diferenciar lo Difícil de lo Imposible

Es nuestro trabajo hacer lo difícil y discernir lo
imposible. Desde el punto de vista de la mayoría de los programadores
activos, algo es imposible si no puede ser desarrollado a partir de un
sistema simple o no puede ser estimado. Mediante esta definición lo
que se denomina investigación es imposible. Un gran volumen de mero trabajo es difícil, pero no necesariamente imposible.

La distinción no es jocosa debido a que se te puede
pedir muy bien hacer lo que es prácticamente imposible, ya sea desde
un punto de vista científico o desde un punto de vista de la
ingeniería de software. Luego se vuelve tu trabajo ayudar al
emprendedor a encontrar una solución razonable la cual es meramente difícil
y que sea más de lo que querían. Una solución es meramente difícil
cuando puede ser confidencialmente calendarizada y son comprendidos los
riesgos.

Si es imposible satisfacer un requerimiento vago, tal
como ‘Construye un sistema que computará el más atractivo estilo y
color de cabello para cualquier persona.’ Si el requerimiento puede
hacerse más expresivo, se volverá a menudo meramente difícil, tal como
‘Construye un sistema para computar un estilo y color atractivo de
cabello para una persona, permitiéndoles previsualizarlo y hacer
cambios, y tener la satisfacción del cliente basado en que el estilo
original sea tan grandioso que hagamos mucho dinero.’ Si no hay una
definición expresiva, no tendrás éxito.

Cómo Utilizar Lenguajes Embebidos

incrustar un lenguaje de programación dentro de un
sistema tiene una fascinación casi erótica para un programador. Es uno
de los más creativos actos que pueden ser realizados. Hace al sistema
tremendamente poderoso. Te permite ejercitar tus habilidades más
creativas y prometeas. Convierte al sistema en tu amigo.

Todos los mejores editores de texto del mundo tienen
lenguajes embebidos. Este puede ser usado hasta el punto que la
audiencia pretendida pueda dominar el lenguaje. Por supuesto, el uso
del lenguaje puede ser opcional, como lo es en los editores de texto,
de tal manera que los iniciados puedan usarlo y nadie más tenga que
hacerlo.

Yo y muchos otros programadores hemos caído en la
trampa de crear lenguajes embebidos de propósito general. Caí en ello
dos veces. Ya existen muchos lenguajes diseñados específicamente para
ser lenguajes embebidos. Deberías pensarlo dos veces antes de crear
uno nuevo.

La verdadera pregunta que uno debe hacerse a sí mismo
antes de incrustar un lenguaje es: ¿Funciona esto con o en contra de
la cultura de mi audiencia? Si tu audiencia pretendida es
exclusivamente no programadores, ¿cómo ayudará? Si tu audiencia
pretendida es exclusivamente programadores, ¿preferirían ellos una
interface de programación de aplicaciones (API)? ¿Y qué lenguaje será?
Los programadores no desean aprender un nuevo lenguaje que sea
estrechamente usado; pero si encaja con su cultura no tendrán que
invertir mucho tiempo en aprenderlo. Es una broma crear un nuevo
lenguaje. Pero no deberíamos permitir que nos cieguen las necesidades
del usuario. A menos que tengas algunas necesidades e ideas
verdaderamente originales, ¿por qué no usar un lenguaje existente de
tal manera que puedas aprovechar la familiaridad que los usuarios ya
tienen con él?

Escogiendo Lenguajes

El programador solitario que ama su trabajo (un
hacker) puede elegir el mejor lenguaje para la tarea. La mayoría de
los programadores activos tienen muy poco control del lenguaje que
usarán. Generalmente, este punto es dictado por jefes encopetados
quienes están haciendo una decisión política, en lugar de una decisión
tecnológica, y carecen del coraje para promover una herramienta no
convencional aún cuando saben, a menudo con conocimiento de primera
mano, que la herramienta menos aceptada es la mejor. En otros casos el
verdadero beneficio de la unidad entre el equipo, y en alguna
extensión con una comunidad más grande, excluye la elección por parte
del individuo. A menudo los administradores se conducen por la
necesidad de ser capaces de contratar programadores con experiencia en
un lenguaje dado. Sin duda están sirviendo a lo que ellos perciben
como el mejor interés del proyecto o la compañía, y deben ser
respetados por eso. Sin embargo, personalmente creo que esto es el mayor
desperdicio y la práctica errónea más común con la que probablemente
te encuentres.

Pero por supuesto, las cosas no son nunca
unidimensionales. Incluso si se ordena usar un lenguaje central y está
más allá de tu control, a menudo es el caso que las herramientas y
otros programas pueden y deberían ser escritos en un lenguaje
diferente. Si un lenguaje debe ser incrustado (¡y deberías siempre
considerarlo!) la escogencia del lenguaje dependerá mucho de la cultura
de los usuarios. Uno debería tomar ventaja de esto para servir a tu
compañía o proyecto mediante el uso del mejor lenguaje para el
trabajo, y al hacerlo así haces el trabajo más interesante.

Los lenguajes de programación deberían ser llamados en realidad notaciones
en el sentido que aprender uno no es del todo tan difícil como
aprender un lenguaje natural. Para los principiantes y para algunos
foráneos «aprender un nuevo lenguaje» parece una tarea dantesca; pero
después de que tienes tres bajo tu faja es realmente sólo cuestión de
familiarizarse con las bibliotecas disponibles. Uno tiende a pensar
de un gran sistema que tiene componentes en tres o cuatro lenguajes
como una mezcolanza desordenada; pero yo argumento que tal sistema es
en muchos casos más fuerte que un sistema hecho en un único lenguaje
de varias formas:

  • Hay necesariamente un débil acoplamiento entre los componentes
    que están escritos en diferentes notaciones (aunque quizá sin
    interfaces limpias),
  • Puedes evolucionar a un nuevo lenguaje o plataforma fácilmente al reescribir cada componente de manera individual,
  • Es posible que alguno de los módulos esté realmente actualizado.

Algunos de esos efectos pueden ser solamente
sicológicos; pero la sicología importa. Al final los costos de la
tiranía del lenguaje sobrepasan cualquier ventaja que provea.

Comprometiéndote Sabiamente

Cómo Combatir Presión de Calendario

La presión de tiempo de mercadeo es la presión para
entregar un buen producto rápidamente. Es bueno debido a que refleja
una realidad financiera, y es saludable hasta cierto punto. La presión
de tiempo de mercadeo es la presión para entregar algo más rápido de
lo que puede ser entregado y es pródigo, insalubre, y muy común.

La presión del cronograma existe por varias razones.
La gente que trabaja con programadores no aprecia completamente la
fuerte ética de trabajo que tenemos y cuán divertido es ser un
programador. Quizá debido a que proyectan su propio comportamiento en
nosotros, creen que pidiéndolo más pronto nos hará trabajar más duro
para tenerlo ahí más pronto. Esto en realidad sea probablemente cierto,
pero el efecto es muy pequeño, y el daño muy grande. Por lo demás, no
tienen visibilidad de lo que realmente se requiere para producir
software. No son capaces de verlo, y no son capaces de crearlo ellos
mismos, la única cosa que pueden hacer es ver la presión de tiempo de
mercadeo y molestar a los programadores por ello.

La clave para combatir la presión del calendario es
simplemente convertirla en presión de tiempo de mercadeo. La manera de
hacer esto es dar visibilidad dentro de la relación entre el trabajo
disponible y el producto. Producir un estimado honesto, detallado, y
sobre todo, comprensible de todo el trabajo involucrado es la
mejor forma de hacer esto. Tiene la ventaja agregada de permitir que
las buenas decisiones de administración sean tomadas sobre posibles
negociaciones de funcionalidades.

El conocimiento clave que el estimado debe hacer claro
es que el trabajo es un fluido casi incomprensible. No puedes
empaquetar más en una medida de tiempo más de lo que podrías
empaquetar más agua en un contenedor por encima de la capacidad del
volumen de ese contenedor. En un sentido, un programador nunca debería
decir ‘no’, sino más bien decir ‘¿Qué cederás para obtener lo que
quieres?’ El efecto de producir estimados claros será incrementar el
respeto por los programadores. Así es como otros profesionales se
comportan. El trabajo duro de los programadores será visible.
Establecer un cronograma no realista será también doloroso para todos.
Los programadores no pueden ser burlados. Es irrespetuoso y
desmoralizador pedirles que hagan algo poco realista. La Programación
Extrema amplifica esto y construye un proceso alrededor de ello;
Espero que cada lector será lo suficientemente afortunado para usarlo.

Cómo Comprender al Usuario

Es tu deber comprender al usuario, y ayudar a tu jefe a
comprender al usuario. Debido a que el usuario no está tan
íntimamente involucrado en la creación de tu producto como lo estás
tú, se comportan de manera un poco diferente:

  • El usuario generalmente hace pronunciamientos cortos.
  • El usuario tiene su propio trabajo; pensarán principalmente en pequeñas mejoras de tu producto, no en grandes mejoras.
  • El usuario no puede tener una visión que represente a todo el cuerpo completo de los usuarios de tu producto.

Es tu deber darles lo que realmente quieren y no lo
que ellos dicen que quieren. Sin embargo, es mejor proponérselo a
ellos y lograr que concuerden en que tu propuesta es lo que realmente
quieren antes de que comiences, pero puede que ellos no tengan la
visión para hacer esto. Tu confianza en tus propias ideas sobre esto
debería variar. Debes cuidarte tanto de la arrogancia como de la falsa
modestia en términos de saber lo que realmente quiere el cliente. Los
programadores están entrenados para diseñar y crear. Los investigadores
de mercado están entrenados para determinar lo que la gente quiere.
Esos dos tipos de personas, o dos modos de pensar en la misma persona,
trabajando armoniosamente juntos dan la mejor oportunidad para
formular la visión correcta.

Entre más tiempo pases con los usuarios estarás en
mejor capacidad para comprender lo que en realidad será exitoso.
Deberías probar tus ideas frente a ellos tanto como puedas. Deberías
comer y beber con ellos si puedes.

Guy Kawasaki [Rules] ha enfatizado la importancia de observar lo que tus usuarios hacen además de escucharlos.

Creo que los contratistas y consultores a menudo
tienen tremendos problemas para lograr que sus clientes clarifiquen en
sus propias mentes lo que realmente quieren. Si intentas ser un
consultor, te sugiero elegir a tus clientes basado en su claridad
mental tanto como por sus billeteras.

Cómo Obtener una Promoción

Para ser promovido a un rol, primero interpreta ese rol.

Para ser promovido a un título, determina lo que se espera de ese título y haz eso.

Para obtener un aumento de sueldo, negocia armado de información.

Si sientes como que estás pasado para una promoción,
habla con tu jefe acerca de ello. Pregúntale explícitamente qué
necesitas hacer para ser promovido, e intenta hacerlo. Esto suena
triste, pero muy a menudo tu percepción de lo que necesitas hacer
diferirá considerablemente de la de tu jefe. Esto también prenderá a
tu jefe a ti de alguna manera.

La mayoría de los programadores probablemente tienen
de alguna forma un exagerado sentido de sus capacidades relativas
—después de todo, ¡no podemos estar todos en el top 10%! Sin
embargo, he visto algunas personas que fueron seriamente inapreciadas.
Uno no puede esperar que la evaluación de todos coincida
perfectamente con la realidad todas las veces, pero pienso que las
personas son en general moderadamente justas, con una advertencia: no
puedes ser apreciado sin visibilidad en tu trabajo. A veces, hacer to
happenstance o por hábitos personales, alguien no será notado mucho.
Trabajar mucho en casa o estando geográficamente separado de tu equipo
y de tu jefe hace esto especialmente difícil.

Sirviendo a Tu Equipo

Cómo Desarrollar Talento

Nietschze exageró cuando dijo [Stronger]:

Lo que no me destruye, me hace más fuerte.

Tu más grande responsabilidad es hacia tu equipo.
Deberías conocer bien a cada uno de ellos. Deberías esforzar a tu
equipo, pero no sobrecargarlos. Usualmente deberías hablar con ellos
sobre la forma en que están siendo esforzados. Si ellos han comprado
la idea, estarán bien motivados. En cada proyecto, o en cada otro
proyecto, trata de esforzarlos tanto de una forma que ellos sugieran
como de una que pienses que será buena para ellos. Esfuérzalos no
dándoles más trabajo, sino dándoles una nueva habilidad o mejor aún un
nuevo rol que jugar dentro del equipo.

Deberías permitir que la gente (incluyéndote a ti
mismo) falle ocasionalmente y deberías planear alguna falla en tu
calendario. Si no hay ninguna falla, no puede haber sentido de la
aventura. Si no hay fallas ocasionales, no estás intentándolo lo
suficiente. Cuando alguien falla, deberías ser tan gentil como puedas
con ellos aunque cuida de no tratarlos como si hubieses tenido éxito.

Intenta conseguir que cada miembro del equipo compre
la idea y esté bien motivado. Pregúntale a cada uno de ellos
explícitamente lo que necesitan para estar bien motivados si no lo
están. Puede que tengas que dejarlos insatisfechos, pero deberías
saber qué desean todos.

No puedes rendirte con alguien que no está llevando
intencionalmente su parte de la carga debido a una baja moral o
insatisfacción y sólo dejarlos que sean negligentes o estén inactivos o
flojos. Debes intentar tenerlos a todos bien motivados y productivos.
Mientras tengas la paciencia, mantén esto. Cuando tu paciencia se
agote, despídelos. No puedes permitir que alguien que está
intencionalmente trabajando por debajo de su nivel permanezca en el
equipo, puesto que no es justo para el equipo.

Haz claro a los miembros fuertes de tu equipo que
piensas que ellos son fuertes diciéndolo en público. Las alabanzas
deberían ser públicas y las críticas en privado.

Los miembros fuertes del equipo tendrán naturalmente
tareas más difíciles que los miembros débiles del equipo. Esto es
perfectamente natural y nadie estará molesto por ello mientras todos
trabajen duro.

Es un hecho real que no se refleja en los salarios que
un buen programador es más productivo que 10 malos programadores.
Esto crea una extraña situación. A menudo será cierto que podrías
moverte más rápido si tus programadores débiles se apartaran del
camino. Si hicieras eso harías de hecho más progreso a corto plazo.
Sin embargo, tu tribu perdería algunos beneficios importantes, por
ejemplo el entrenamiento de los miembros débiles, la diseminación del
conocimiento tribal, y la capacidad para recuperarte de la pérdida de
miembros fuertes. El fuerte debe ser gentil en este aspecto y
considerar el punto desde todos los ángulos.

A menudo puedes dar a los miembros más fuertes del equipo tareas desafiantes, pero cuidadosamente delineadas.

Cómo Elegir Sobre Qué Trabajar

Tú balanceas tus necesidades personales frente a las
necesidades del equipo al escoger sobre cuál aspecto de un proyecto
trabajar. Deberías hacerlo en lo que eres mejor, pero trata de
encontrar una forma de esforzarte a ti mismo no por tomar más trabajo
sino mediante el ejercicio de una nueva habilidad. Las habilidades de
liderazgo y comunicación son más importantes que las habilidades
técnicas. Si eres muy fuerte, toma las tareas más difíciles o riesgosas,
y hazlas tan pronto como sea posible en el proyecto para decrementar
el riesgo.

Cómo Obtener lo Máximo de Tus Compañeros de Equipo

Para obtener lo mejor de tus compañeros de equipo,
desarrolla un buen espíritu de equipo y trata de mantener a cada
individuo tanto personalmente desafiado como personalmente
comprometido.

Para desarrollar espíritu de equipo, el dar a granel
cosas como las ropas con logotipos y las fiestas son buenas, pero no
tan buenas como el respeto personal. Si todos respetamos a todos los
demás, nadie querrá dejar a nadie bajo de ánimo. El espíritu de equipo
se crea cuando la gente hace sacrificios por el equipo y piensa en
términos del bienestar del equipo antes del propio bienestar personal.
Como un líder, no puedes pedir más de lo que tú mismo puedes dar al
respecto.

Una de las claves para el liderazgo de equipo es
facilitar el consenso de manera tal que todos han comprado la idea.
Esto ocasionalmente significa permitir a tus compañeros de equipo
estar equivocados. O sea, si ello no daña demasiado al proyecto, debes
permitir a parte de tu equipo hacer cosas a su propio modo, basado en
el consenso, incluso si crees con gran confianza que es equivocado
hacerlo. Cuando esto suceda, no estés en desacuerdo, simplemente
disiente abiertamente y acepta el consenso. No suenes como si estuvieras
herido, o como que estás siendo forzado a ello, simplemente establece
que disientes pero que piensas que el consenso del equipo es más
importante. Esto hará que a menudo se echen atrás. No insistas en que
sigan con su plan inicial si se echan atrás.

Si hay un individuo que no consienta después de que
has discutido los puntos desde todos los ángulos apropiados,
simplemente afirma que tienes que tomar una decisión y cuál es tu
decisión. Si hay una manera de juzgar si tu decisión estará equivocada
o si luego demostrará estar equivocada, cambia tan rápidamente como
puedas y reconoce a las personas que estuvieron en lo correcto.

Pregunta a tu equipo, tanto como grupo como de forma
individual, qué piensan que crearía un espíritu de equipo y en qué
consiste un equipo efectivo.

Elogia frecuentemente en lugar de hacerlo
profusamente. Especialmente elogia a esos que disienten contigo cuando
se lo merecen. El elogio en público y la crítica en privado; con una
excepción: a veces la exaltación o la corrección de una falla no puede
hacerse sin dirigir la atención a la embarazosa falla original, así
que la exaltación debería ser elogiada en privado.

Cómo Dividir Problemas

Es divertido tomar un proyecto de software y dividirlo
en tareas que serán llevadas a cabo por individuos. Esto debería
hacerse en etapas tempranas. A los administradores a veces les gusta
pensar que un estimado puede hacerse sin consideración hacia los
individuos que realizarán el trabajo. Esto es imposible puesto que la
productividad de los individuos varía muy ampliamente. El que tiene el
conocimiento sobre un componente también cambia constantemente y puede
tener un efecto de un orden de magnitud sobre el desempeño.

Al igual que un compositor considera el timbre del
instrumento que tocará una nota musical o el coach de un equipo
atlético considera la fortaleza de cada jugador, el líder de equipo
experimentado usualmente no será capaz de separar la división del
proyecto en tareas de los miembros del equipo a las cuales serán
asignadas. Esta es parte de la razón por la que un equipo de alta
ejecución no debería ser dividido.

Hay un cierto peligro en ello dado que la gente se
aburrirá a medida que construyen sus fortalezas y nunca mejoran sus
debilidades o aprenden otras nuevas. Sin embargo, la especialización
es una muy útil herramienta de productividad cuando no es
sobreutilizada.

Cómo Manejar las Tareas Aburridas

A veces no es posible evitar las tareas aburridas que
son críticas para el éxito de la compañía o el proyecto. Esas tareas
pueden en realidad dañar la moral de quienes tienen que hacerlas. La
mejor técnica para lidiar con esto es invocar o promover la virtud de
la Pereza del programador Larry Wall. Intenta hallar alguna forma de
hacer que la computadora haga la tarea por ti o ayuda a tus compañeros
de equipo a hacer esto. Trabajar una semana en un programa para hacer
una tarea que tomará una semana hacerlo a mano tiene la gran ventaja de
ser más educacional y a veces más repetible.

Si todo lo demás falla, pide disculpas a quienes
tienen que hacer la tarea aburrida, pero bajo ninguna circunstancia
les permitas hacerla solos. Como mínimo asigna un equipo de dos para
hacer el trabajo y promueve el trabajo en equipo saludable para lograr
tener la tarea hecha.

Cómo Conseguir Apoyo para un Proyecto

Para conseguir apoyo para un proyecto, crea y comunica
una visión que demuestre el valor real a la organización como un
todo. Intenta dejar que otros compartan la creación de tu visión. Esto
les da una razón para apoyarte y te da el beneficio de sus ideas.
Individualmente recluta personal de apoyo clave para tu proyecto.
Siempre que sea posible, muestra, no cuentes. Si es posible, construye
un prototipo o una maqueta para demostrar tus ideas. Un prototipo es
siempre poderoso pero en software es muy superior a cualquier
descripción escrita.

Cómo Hacer Crecer un Sistema

La semilla de un árbol contiene la idea del adulto
pero no comunica completamente la forma y la potencia del adulto. El
embrión crece. Se vuelve más grande. Se parece más al adulto y tiene
la mayoría de las características. Eventualmente produce frutos. Más
tarde, muere y su cuerpo alimenta a otros organismos.

Tenemos la lujuria de tratar igual al software. Un
puente no es así; nunca hay un bebé puente, sino meramente un puente
no finalizado. Los puentes son mucho más simples que el software.

Es bueno pensar en el software como algo en
crecimiento, debido a que nos permite hacer un progreso útil antes de
que tengamos una imagen mental perfecta. Podemos obtener
retroalimentación de los usuarios y usar eso para corregir el
crecimiento. Podar las hojas débiles es saludable.

El programador debe diseñar un sistema finalizado que
pueda ser entregado y usado. Pero el programador avanzado debe hacer
más. Debes diseñar una ruta de crecimiento que concluya en el sistema
finalizado. Es tu trabajo tomar el germen de una idea y construir una
ruta que la convierta tan suavemente como sea posible en un artefacto
útil.

Para hacer esto, debes visualizar el resultado final y
comunicarlo de una forma que el equipo de ingenieros pueda
emocionarse. Pero también debes comunicarles una ruta que vaya de
dondequiera que estén ahora hacia donde quieren estar sin grandes
saltos. El árbol debe permanecer vivo todo el tiempo; no puede estar
muerto en un punto y resucitar más tarde.

Este acercamiento es capturado en un desarrollo en
espiral. Los hitos que nunca están demasiado alejados son usados para
marcar el progreso a lo largo del camino. En el ambiente
ultracompetitivo de los negocios, es mejor si los hitos pueden ser
liberados y hacer dinero tan pronto como sea posible, incluso si están
demasiado lejos de un punto final bien diseñado. Uno de los trabajos
del programador es balancear el pago inmediato frente al futuro
mediante la sabia elección de un camino de crecimiento expresado en
hitos.

El programador avanzado tiene la triple responsabilidad de hacer crecer el software, los equipos, y a las personas.

Un lector, Rob Hafernik, envió este comentario sobre esta sección que no puedo menos que citarlo completo:

Pienso que subenfatizas la importancia aquí.
No son sólo sistemas, sino algoritmos, interfaces de usuario, modelos
de datos, y cosas así. Es absolutamente vital a medida que
trabajas en un gran sistema tener progreso medible hacia metas
intermedias. Nada es tan malo como el horror especial de llegar al
final y descubrir que toda la cosa simplemente no va a funcionar (mira
la reciente debacle del Sistema Voter News). Yo iría más allá y lo
afirmaría como una ley de la naturaleza: ningún sistema grande y
complejo puede ser implementado de la nada, puede solamente evolucionar de un sistema simple a uno complejo en una serie de pasos intencionales.

A lo cual uno puede solamente replicar ¡Fiat lux!

Cómo Comunicar Bien

Para comunicarte bien, tienes que reconocer cuán
difícil es. Es una habilidad en sí misma. Se hace más difícil por el
hecho de que las personas con quien tienes que comunicarte son
inperfectas. Ellas no trabajan duro en comprenderte. Hablan y escriben
pobremente. Están a menudo sobretrabajadas o aburridas, y, como
mínimo, algo enfocadas en su propio trabajo más que en los tópicos más
grandes que puedes estar comentando. Una de las ventajas de tomar
clases y practicar la escritura, el hablar en público, y escuchar es
que si te vuelves bueno en ello puedes más fácilmente ver donde yacen
los problemas y cómo corregirlos.

El programador es un animal social cuya sobrevivencia
depende de la comunicación con su equipo. El programador avanzado es
un animal social cuya satisfacción depende de la comunicación con
gente fuera de su equipo.

El programador trae orden al caos. Una forma
interesante de hacer esto es iniciar una propuesta de algún tipo fuera
del equipo. Esto puede ser hecho en un formato strawman o en formato white-paper
o sólo verbalmente. Este liderazgo tiene la tremenda ventaja de fijar
los términos del debate. También te expone a críticas, y peor, al
rechazo y al descuido. El programador avanzado debe estar preparado
para aceptar esto, debido a que tiene un poder único y por lo tanto
una responsabilidad única. Los emprendedores que no son programadores
necesitan que los programadores aporten liderazgo de algunas maneras.
Los programadores son la parte del puente entre las ideas y la
realidad que descansa en la realidad.

No he dominado bien la comunicación, pero lo que estoy
intentando actualmente es un método de cuatro pasos: Después de que
tengo mis ideas en orden y estoy completamente preparado, trato de
hablar verbalmente, doy a las personas un papel en blanco (sobre papel
real, al igual que electrónicamente), les muestro un demo, y luego
pacientemente repito este proceso. Pienso que muchas veces no somos lo
suficientemente pacientes en este tipo de comunicación difícil. No
deberías descorazonarte si tus ideas no son inmediatamente aceptadas. Si
has invertido energía en su preparación, nadie pensará pobremente de
ti por ello.

Cómo Decirle a la Gente Cosas que No Desean Escuchar

A menudo tendrás que decirle a la gente cosas que los
hará sentir incómodos. Recuerda que estás haciendo esto por una razón.
Aún si no puede hacerse nada por el problema, estás diciéndoles tan
pronto como es posible de tal manera que estarán bien informados.

La mejor manera de decirle a alguien sobre un problema
es ofrecerles a la vez una solución. La segunda mejor manera es
apelar a ellos para que ayuden con el problema. Si existe el peligro
de que no serás creído, deberías conseguir algún soporte para tu
afirmación.

Una de las cosas más comunes e implacenteras que
tendrás que decir es, ‘El calendario tendrá que correrse.’ El
programador consciente odia decir eso, pero debe decirlo tan pronto
como sea posible. No hay nada peor que posponer la acción cuando se
corre un hito, incluso si la única acción es informar a todos. Al
hacer esto, es mejor hacerlo como equipo, al menos en espíritu, si no
puedes físicamente. Desearás la opinión de tu equipo tanto acerca de
dónde están como sobre qué puede hacerse al respecto, y el equipo
tendrá que enfrentar las consecuencias contigo.

Cómo Lidiar con Mitos Administrativos

La palabra mito algunas veces significa
ficción. Pero tiene una connotación más profunda. También significa
una historia de religiosa significancia que explica el universo y la
relación de la humanidad con él. Los administradores tienden a olvidar
lo que ellos aprendieron como programadores y creen en ciertos mitos.
Sería tan rudo como exitoso tratar de convencerlos de que esos mitos
son falsos como el tratar de desilusionar a una persona devotamente
religiosa de sus creencias. Por esa razón, deberías reconocer estas
creencias como mitos:

  • Más documentación es siempre mejor. (Ellos la requieren, pero no quieren que gastes tiempo en ella.)
  • Los programadores pueden ser equiparados. (Los programadores varían por un orden de magnitud.)
  • Los recursos pueden ser agregados a un proyecto retrasado para
    acelerarlo. (El costo de la comunicación con las nuevas personas es
    casi siempre más penalizador que útil.)
  • Es posible estimar la confiabilidad del desarrollo del software. (No es posible ni siquiera teóricamente.)
  • La productividad de los programadores puede ser medida en
    términos de alguna métrica simple, como las líneas de código. (Si la
    concisión es poder, las líneas de código son malas, no buenas.)

Si tienes oportunidad, puedes intentar explicar esas
cosas, pero no te sientas mal si no tienes éxito y no dañes tu
reputación confrontando esos mitos beligerantemente. Cada uno de esos
mitos refuerza la idea del administrador de que tienen un control real
sobre lo que está pasando. La verdad es que los administradores lo
facilitan si son buenos, y lo impiden si son malos.

Cómo Lidiar con el Caos Organizacional

A menudo hay breves periodos de gran caos
organizacional, tales como despidos, compras, IPOs, despidos, nuevas
contrataciones, y cosas así. Son trastornantes para todos, pero quizá
un poco menos para el programador cuya autoestima personal está basada
en la capacidad más que en la posición. El caos organizacional es una
gran oportunidad para que los programadores ejerciten su poder
mágico. He guardado esto para el final porque es un profundo secreto
tribal. Si no eres un programador, por favor deja de leer ahora.

Los ingenieros tienen el poder de crear y sostener.

Los no ingenieros pueden ordenar a la gente a su
alrededor pero, en una compañía típica de software, no pueden crear ni
sostener nada sin los ingenieros, al igual que los ingenieros
típicamente no pueden vender un producto o administrar un negocio
efectivamente. Este poder es a prueba de casi todos los problemas
asociados con la mutilación organizacional temporal. Cuando lo tienes
deberías ignorar el caos completamente y continuar como si nada
estuviera pasando. Puedes, por supuesto, ser despedido, pero si eso
pasa probablemente puedes conseguir un nuevo trabajo debido al poder
mágico. Muy comúnmente, alguna persona estresada que no tiene el poder
mágico vendrá a tu cubículo y te dirá algo estúpido. Si estás
realmente seguro de que es estúpido, es mejor sonreír y asentir hasta
que se vaya y luego continuar haciendo lo que sabes es lo mejor para
la compañía.

Si eres un líder, dile a tu gente que haga lo mismo y
diles que ignoren lo que los demás les digan. Este curso de acción es
lo mejor para ti en lo personal, y es lo mejor para tu compañía o
proyecto.

Glosario

Este es un glosario de términos usados en este ensayo.
No tiene necesariamente un significado estandarizado para otras
personas. Eric S. Raymond ha compilado un glosario masivo e
informativo [HackerDict] que más que sorprendente puede ser
placenteramente leído de tapa a tapa una vez que puedas apreciar una
fracción de él.

unk-unk
Argot para unknown-unknown. Los problemas que en la actualidad no
pueden ni siquiera ser conceptualizados que robarán tiempo del
proyecto y destrozarán el calendario.
jefe
La persona o entidad que te da tareas. En algunos casos este
puede ser a la larga el público. La persona que establece tus tareas.
En algunos casos, el usuario es el jefe.
printlining
La inserción de sentencias en un programa en una base
estrictamente temporal que arroje información acerca de la ejecución
del programa para el propósito de la depuración.
logging
La práctica de escribir un programa de tal manera que pueda
producir una bitácora de salida configurable describiendo su
ejecución.
divide y vencerás
Una técnica de diseño top-down y, aún más importante, de
depuración que consiste en la subdivisión de un problema o un misterio
en problemas o misterios progresivamente más pequeños.
vaporware
Promesas de software ilusorias y a menudo decepcionantes que no
están todavía a la venta y, tan a menudo como no, nunca se
materializarán en algo sólido.
tribu
La gente con la que compartes tu lealtad hacia una meta común. Un
grupo de personas con la que compartes afinidad cultural y lealtad.
frutas de cuelgue bajo
Grandes mejoras que cuestan poco.
Emprendedor
El iniciador de proyectos.
basura
Objetos que no se necesitan más que se mantienen en memoria. Memoria asignada que ya no tiene un significado útil.
negocio
Un grupo de personas organizadas para hacer dinero.
compañía
Un grupo de personas organizadas para hacer dinero.
ceguera de desplazamiento
El efecto de ser incapaz de encontrar la información que
necesitas debido a que está sepultada en muchísima información menos
interesante.
reloj de pared
El tiempo real como es medido por un reloj de pared, opuesto al tiempo de CPU.
cuello de botella
La más importante limitación en el desempeño de un sistema. Una constricción que limita el desempeño.
maestro
Una pieza única de información desde la cual se derivan todas las
copias cacheadas que sirve como la definición oficial de esos datos.
heap asignado
Memoria de la que puede decirse que está asignada en el heap cuando el mecanismo para liberarla es complicado.
recolector de basura
Un sistema para reciclar basura.
fuga de memoria
La indeseada colección de referencias a objetos que evita la
recolección de basura (¡o un error en el recolector de basura o en el
sistema de administración de memoria!) que causa que el programa
incremente gradualmente sus demandas de memoria en el tiempo.
Programación Extrema
Un estilo de programación que enfatiza la comunicación con el cliente y las pruebas automatizadas.
golpear la pared
Quedarse sin un recurso específico ocasionando que se degrade el desempeño abruptamente en lugar de hacerlo gradualmente.
programación especulativa
Producir una funcionalidad antes de que realmente se sepa si esa funcionalidad será útil.
ocultamiento de información
Un principio de diseño que busca mantener las cosas
independientes y desacopladas mediante el uso de interfaces que
exponen tan poca información como sea posible.
programación orientada a objetos
Un estilo de programación que enfatiza la administración del estado dentro de los objetos.
lenguajes de comunicación
Un lenguaje diseñado primariamente para la estandarización más que para la ejecución.
cajas y flechas
Un estilo flojo e informal de hacer diagramas que consiste de
cajas y flechas dibujadas entre esas cajas para mostrar las
relaciones. Esto contrasta con las metodologías formales de
diagramación, tales como la del UML.
lingua franca
Un lenguaje tan popular como para el estándar de facto para su
campo, tal como el francés lo fue una vez para la diplomacia
internacional.
comprar vs. construir
Un adjetivo que describe una elección entre gastar dinero al comprar software o escribirlo tú mismo.
mero trabajo
Trabajo que requiere poca creatividad y vincula poco riesgo. El mero trabajo puede ser fácilmente estimado.
notación de programación
Un sinónimo para los lenguajes de programación que enfatiza la
naturaleza matemática del lenguaje de programación y su relativa
simplicidad comparada con los lenguajes naturales.
strawman
Un documento destinado a ser el punto de inicio de una discusión
técnica. Un strawman puede conducir a un stickman, a un tinman, a un
woodman, a un ironman, etc.
white-paper
Un documento informativo que a menudo es destinado para explicar o
vender una idea o producto a una audiencia diferente a la de los
programadores de esos productos o ideas.

Tabla de Contenido

Bibliography/Websiteography

Bibliografía/Websiteografía

Books

[Rules00] Guy Kawasaki, Michelle Moreno, y Gary Kawasaki. 2000. HarperBusiness. Rules for Revolutionaries: The Capitalist Manifesto for Creating y Marketing New Products y Services.

[RDev96] Steve McConnell. 1996. Microsoft Press. Redmond, Wash. Rapid Development:Taming Wild Software Schedules.

[CodeC93] Steve McConnell. 1993. Microsoft Press. Redmond, Wash. Code Complete.

[XP99] Kent Beck. 1999. 0201616416. Addison-Wesley. Extreme Programming Explained: Embrace Change.

[PlanXP00] Kent Beck y Martin Fowler. 2000. 0201710919. Addison-Wesley. Planning Extreme Programming.

[Prag99] Andrew Hunt, David Thomas, y Ward Cunningham. 1999. 020161622X. Addison-Wesley. The Pragmatic Programador: From Journeyman to Master.

[Stronger] Friedrich Nietzsche. 1889. Twilight of the Idols, «Maxims y Arrows», sección 8..

Web Sites

[PGSite] Paul Graham. 2002. Articles on his website: http://www.paulgraham.com/articles.html. All of them, but especialmente «Beating the Averages».

[Hacker] Eric S. Raymond. 2003. Cómo to Become a Hacker. http://www.catb.org/~esr/faqs/hacker-Cómoto.html.

[HackDict] Eric S. Raymond. 2003. The New Hacker Dictionary. http://catb.org/esr/jargon/jargon.html.

[ExpCS] Edsger W. Dijkstra. 1986. How Experimental is Computing Science?. http://www.cs.utexas.edu/usuarios/EWD/ewd09xx/EWD988a.PDF.

[Knife] Edsger W. Dijkstra. 1984. On a Cultural Gap. http://www.cs.utexas.edu/usuarios/EWD/ewd09xx/EWD913.PDF .

Get a free website at Webs.com
Esta entrada fue publicada en Android, IOS, JAVA. Guarda el enlace permanente.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.