Desarrollo de software en una PYME

Estos escritos reflejan parte de mi aprendizaje luego de más de 5 años desarrollando proyectos software en una PYME. Han sido publicados previamente en mi blog como textos individuales, pero creo que tienen suficiente entidad como conjunto para merecerse un espacio propio.

  • Introducción
    • De qué hablo cuando hablo de programar (texto original, 7 Septiembre 2015)
  • Prospectiva y análisis
  • Desarrollo del proyecto
    • Inversión y amortización en la selección tecnológica (texto original, 17 Febrero 2015)
    • Diseño y testeabilidad (texto original, 17 Marzo 2015)
    • Arquitecturas para la participación (texto original, 16 Enero 2016)

De qué hablo cuando hablo de programar

A grandes rasgos, como programador, me puedo identificar con el trabajo que llevan a cabo un carpintero, escritor, modista o diseñador industrial. Todos ellos crean una estructura donde no la hay y le dan una forma agradable que la gente quiere usar. Lo que es completamente diferente con respecto a ellos son mis herramientas, las tareas diarias que realizo y el conocimiento específico que necesito para llevar a cabo mi trabajo. Cada oficio tiene sus cosas, aunque existan lecciones compartidas de unos a otros.

Las actividades del día a día

En mi empresa, creamos productos para organizaciones. Diseñamos herramientas para la toma de decisiones y compartir información. En ese contexto, mi día a día pivota en torno a 3 actividades diferenciadas:

  • entender los procesos del cliente, para lo que es necesario conocer el dominio en el que trabajas: ¿qué datos se recogen? ¿qué tareas necesitan resolver con esos datos? ¿cuáles son los roles de la gente que participa? El objetivo es entender qué hace el cliente para proponer mejores maneras de hacerlo con ayuda de la tecnología. La mejor herramienta que he encontrado en esta actividad es la conversación con el cliente y compañeros. Suelo también dibujar gráficos en papel. En digital menos, porque me lleva más tiempo y el gráfico no tiene vocación de permanencia, es meramente una herramienta para pensar y comunicar.
  • diseñar el producto, crear la herramienta que se adapte al proceso: ¿debemos usar una metáfora de mapa o de ruta? ¿Cómo componer la interfaz? ¿Cuál es el siguiente paso que un usuario debe hacer? En esta actividad el objetivo es determinar cómo un usuario interactúa con el producto y cómo eso da forma al proceso. Uso mucho el papel para comunicar el flujo o composición de las interfaces del producto a mis compañeros y clientes, pero coge relevancia lo digital para mostrar capturas de ejemplo de otros productos, realizar bocetos, etc. Y, por supuesto, un editor de texto (enfocado a programación) para implementar esas ideas. Hay mucho de ajuste en esta actividad, de probar si lo que pensaste inicialmente tiene sentido, de tratar de entender el espacio de la solución y decidirse por lo que mejor encaja. También tiene mucho de pegamento entre el análisis y la programación.
  • dotar de estructura al producto: ¿cómo diseñamos la base de datos? ¿y la arquitectura de mensajes? ¿es necesario ajustar la estructura o conviene generar deuda técnica? El objetivo de esta actividad es construir la solución. Esto es lo que convencionalmente se entiende como programación: escribir en un editor de texto lo que has aprendido del diseño y análisis. Mi principal herramienta es el editor, claro, y las interfaces que me ofrezcan las tecnologías que uso (base de datos, consola, etc). Suelo también garabatear mucho en papel para pensar. Mientras no se nos ocurra algo mejor, el papel me parece la tecnología definitiva para explorar ideas: flexible, rápida y desechable.

Estas actividades no son secuenciales (análisis > diseño > estructura) ni estancas, se retroalimentan y hay ciclos también en ellas.

Capacidades y equipo en contexto

Es importante que el equipo tenga todas estas capacidades, aunque cada persona tendrá fortalezas en un área u otra: alguien puede conocer muy bien el dominio porque ha trabajado en él, otros pueden ser mejores diseñando el producto porque conocen lo que la tecnología puede dar y tienen la empatía suficiente para entender el proceso, etc.
Hay días en que no sé cómo llamarme a mi mismo: ¿analista, diseñador de interacción, programador? Medio en broma, medio en serio, con los íntimos digo que soy fisico-químico de sistemas de control interactivos. La historia del término tiene su gracia y, en verdad, refleja muy bien lo que hago: estudiar las fuerzas y estados por los que un sistema puede pasar y dotarlo de interactividad. No deja de ser una boutade. Tampoco es que me importe no tener un nombre sino muchos dependiendo del contexto. Además, en el sector nadie sabe en realidad cómo llamarse a sí mismo: UX, UA, IxD, diseñador gráfico, programador, programador backend, arquitecto de software, testeador, programador frontend, growth engineer, etc. ¿De verdad necesitamos tantos nombres? Creo que existen porque señalizan cuál es el silo en que te ubicas en una organización, el departamento y nivel de jerarquía. Yo suelo utilizar sólo 3: analista, diseñador de interacción y programador. Creo que comunican las actividades principales y son ampliamente conocidos en el sector, no necesitan ser explicados. Lo que me gusta de ellos es que transmiten una sensación de amplitud, de recoger todo lo que una actividad puede ofrecer; señalan a mi interlocutor que estoy capacitado para hablar con él (que es lo que me interesa de un nombre) evitando el efecto: ah, es que tú sólo haces UX, no te veo como un igual.
Por otro lado, en cuanto a la secuencialidad de las fases habría mucho que decir, pero tiende a ser cierto que por la propia naturaleza del trabajo los ciclos iniciales del proyecto contienen más análisis y los finales menos, por ejemplo. Además, al estudiar lo que hacen otros, me he dado cuenta de que el día a día de los programadores es muy distinto dependiendo cuál sea tu producto y sector: ¿creas productos para organizaciones? ¿juegos? ¿herramientas de publicación? ¿películas? ¿música? No me refiero únicamente a conocimiento especializado (cómo dibujar un mapa, cómo renderizar un personaje en un juego, etc), sino a cosas más amplias que impactan en cómo enfocas tus actividades diarias. Por ejemplo, una arquitectura específica puede tener mucho sentido en un sector pero no en otro simplemente por cosas como cuáles son los canales de distribución de tu producto.

Crear productos, de principio a fin

Cuando hablo de programar, hablo de todo esto. De la actividad que me permite crear productos de principio a fin.
Por desgracia, creo que todavía hoy la visión hegemónica de un programador baila entre la superespecialización de las factorías de software y el vaquero indomable de las startups que puede hacer cualquier cosa desde la soledad de una cafetería. La primera transmite que no eres nadie si no eres el jefe de todos esos compartimentos estancos; la segunda, que no necesitas compañeros y pares para ser mejor y llevar tu proyecto a cabo. Necesitamos otro relato. Necesitamos una visión equilibrada de la programación como trabajo en equipo y carrera a largo plazo.
No me frusto tampoco con esta visión descompensada pues no conviene olvidar que la nuestra es una industria muy joven. Empezamos, ahora, a tener a nuestros propios viejos programadores. Quizás entenderemos de verdad lo que significa programar cuando el tiempo pase y las historias que cuentan los mayores se transmitan entre generaciones. Por eso admiro a personas como Ward Cunningham y Kent Beck que, a pesar de formar parte de los pioneros de la industria, siguen en primera línea a sus 60 años, haciendo lo que se les da bien: crear productos de principio a fin.

Innovar para sobrevivir

Las empresas sacan productos a mercado para ganarse la vida. Pero una vez lo haces, las oportunidades de mantener las ventas/beneficios en el tiempo con el mismo producto son cada vez menores.
Por un lado, en el mercado la oferta de productos similares de menor precior y/o mayor funcionalidad aumenta con el tiempo. Para protegerte, es sensato sacar nuevas versiones que aporten algo nuevo y permitan mantener los márgenes, bien sea consiguiendo nuevos clientes o con la actualización de los actuales a la nueva versión del producto. En esa carrera, llega un punto donde la demanda se resiente: los clientes ya tienen el producto que hace casi todo lo que necesitan, ¿y para qué van a cambiar a una nueva versión con los costes que eso tiene? Por lo que te ves empujado a integrar un número mayor de funcionalidades que van dirigidas a un menor número de usuarios. Si no lo haces bien, es muy fácil acabar con un producto tan lleno de cosas que es imposible que nadie esté contento y hacer la misma tarea les llevará a todos más tiempo. En ocasiones lo mejor es saber decir no:
https://vimeo.com/81544164
Por otro lado, los costes de producir algo que la gente desee comprar aumentan con el tiempo: tu productividad y eficiencia se ven mermadas por adaptaciones del producto a cambios tecnológicos propios o del ecosistema, la complejidad derivada del crecimiento y los compromisos que has tomado con el tiempo. En ocasiones, necesitarás hacer cambios profundos que afectarán a tu base instalada de usuarios, a las que quizás no les interesa el cambio que propones por lo que no actualizarán a la nueva versión o, peor todavía, hablarán mal de tu producto. Esta fuerza no visible te empuja a ser más conservador con lo que haces, con el consecuente coste de oportunidad.
En definitiva, el tiempo y las iteraciones meten presión en tu producto. Una nueva versión o funcionalidad no significa simplemente incluir un icono más en el menú o crear una nueva función en el código. La complejidad aumenta con cada añadido y si no la controlas, tu atractivo en el mercado y tu capacidad de reacción serán cada vez menores.

El corre que te pillo de la industria del software

La historia de la mayoría de empresas de software se podría resumir de esa manera: como un corre que te pillo en el que se puede estar un tiempo indeterminado, con las amenazas constantes de que el mercado llegue a su punto de saturación o tu producto se quede desfasado.
Las compañías están programadas para crear nuevas versiones del producto, pero no nuevos productos. Microsoft, luego de tener el monopolio de los sistemas operativos erró al calcular el impacto que tendría internet con consecuencias en su negocio que duran hasta hoy, siendo Google y Apple los grandes beneficiados. ArcGIS, hace una década el producto cuasi-monopolista del mercado de sistemas de información geográfica, ha visto cómo le crecen los enanos con el inicio de siglo: productos de software libre que lo sustituyen para gran parte de las tareas y compañías como CartoDB o MapBox que han sabido leer mejor en un primer momento las oportunidades de internet para el sector SIG. Casi la totalidad de los productos que ha sacado Adobe después de Illustrator han sido resultado de adquisiciones de otras compañías. Y así un largo etc.

Particularmente con la emergencia de internet y el empuje del software libre, el sector ha sufrido movimientos profundos durante los últimos años, y uno de los patrones que vemos emerger es que las compañías se están moviendo mayoritariamente a un modelo de negocio basado en subscripciones. Un modelo de subscripciones permite reducir el time to market a la vez que los usuarios pagan por las actualizaciones, que no están garantizadas en un modelo de licencia.
Lo cierto es que crear nuevos productos no es sencillo. Sobre todo cuando las fuerzas que degradan tus márgenes son, en un análisis cortoplacista, tan lógicas y apetecibles que es fácil dejarse llevar por ellas: «añade esta funcionalidad, que así firmamos el contrato con este nuevo cliente», «haz un apaño aquí con el código, total es más rápido y funciona lo mismo», etc. En ocasiones, seguro que traen algún beneficio inmediato a corto plazo. Para las empresas que no tenemos un talonario que usar cuando se esté muriendo la gallina de los huevos de oro, esto es un peligro evidente. A falta de talonario, nos toca agudizar el ingenio. Para sobrevivir debemos ser más cuidadosas que las grandes, ampliar miras y aprender a reinventarnos con el tiempo. Vivir arrebatados por el cambio.

¿Qué es una oferta?

Cuando uno habla de compañías de software, en ocasiones se hace necesario diferenciar entre compañías de producto y de servicio. Por la propia naturaleza de cada una, sus fases de comercialización son distintas. En una empresa de servicios cobra especial importancia la construcción de una oferta.
Estos días mi atención ha girado en torno a esta diferencia: ¿qué es una oferta? O más concretamente, ¿qué hacen las compañías de servicio en una oferta que las de producto no hacen o hacen de otra manera?

La oferta como fase de conceptualización del producto

Una oferta pone sobre la mesa lo que se va a hacer y en qué condiciones compensa hacerlo. Exige realizar 2 actividades diferenciadas: problem setting y problem solving, proponer una solución y estimar cuánto lleva su ejecución.
Las compañías de producto también realizan esas actividades, pero las llaman de otra manera: fase de diseño del proyecto, ideación, conceptualización, etc. En muchos sectores (audiovisual, automóviles, etc) en esta fase inicial se realizan prototipos que permiten explorar el espacio de la soluciones, los productos posibles para el problema que uno desea resolver. Si los prototipos convencen y la idea tiene cierto sentido, se consigue presupuesto para llevarla al siguiente paso: producción. En proyectos software es mucho menos habitual ver esto, sin embargo, es igualmente necesario “pensar el producto” y “realizar el producto”. Y aunque uno no desconecta el cerebro y deja de pensar cuando empieza a ejecutar, sí es cierto que con el paso del tiempo, la actividad de “pensar” es reemplazada paulatinamente por la de “ejecutar”.

El contexto de una empresa de servicios

Una oferta para una empresa de servicios es el equivalente de la fase de conceptualización de producto. Pero condensada. Y con restricciones derivadas de que, habitualmente, conocer en detalle los procesos del cliente durante el momento de realizar la oferta es difícil. Tampoco es habitual construir diferentes prototipos que validen la idea y el enfoque. Por todo esto, en una oferta se concentran riesgos derivados de una concepción del producto errada o bien de una estimación optimista de las tareas. Todo aquel que haya participado en ofertas sabe que si esos riesgos emergen durante el proyecto se transforman en retrasos en las entregas, pérdida de dinero o ajustes del alcance, dependiendo de la relación cliente/productor y el tipo de contrato.
Verlo así da un poco de miedo y parecería que las empresas de servicios son unas irresponsables que no se preocupan por pensar. Sin embargo, en muchas ocasiones, estos riesgos se ven mitigados por varios factores:

  • en general, las ofertas se realizan dentro de un dominio (banca, ingeniería civil, etc) donde los analistas tienen experiencia y un conocimiento aproximado de los procesos del cliente.
  • muchos proyectos en empresas de servicios comparten modos de hacer las cosas o código en forma de librerías que el equipo va construyendo, con lo que uno no empieza de cero cada vez.
  • hay casos donde se realiza una primera oferta de análisis, para plantear a posteriori soluciones concretas.
  • es posible incluir tiempo de conceptualización en el proyecto siempre que el cliente sea consciente de que el alcance es abierto y ajustable.
  • ciertos tipos de contratos favorecen que los riesgos de la exploración de los productos posibles sean asumidos por el cliente, por ejemplo, en aquellos con un alcance abierto pero un precio y tiempo fijados.

Sea como sea, una oferta contiene riesgos que es necesario gestionar. Es sin duda un reto combinar la necesidad de innovación ante el agotamiento del mercado con fases de conceptualización de producto generalmente ajustadas.

Análisis orientado a la tarea

«If I’d asked people what they wanted, they would have asked for a better horse»

— Henry Ford

Una de las cosas que uno hace cuando participa en una empresa es preparar ofertas para clientes. En ocasiones, la tarea es sencilla porque el dominio o el problema es muy acotado o ya has hecho cosas similares anteriormente. En otras, sin embargo, es necesario aterrizar una marabunta de ideas inconexas, deseos más allá de la realidad o que el usuario no sabe lo que quiere (simplemente necesita resolver un problema).

De un problema a una solución

Hace años, participé en un proyecto donde el cliente tenía un problema: para compartir información de un proceso de la empresa, los usuarios participantes tenían en su ordenador una jerarquía de carpetas propia, con distintos documentos cada uno que ligaban mediante un código compartido (que tenía, sin embargo, matices para cada usuario). Cuando necesitaban alguna información concreta, se enviaban e-mails entre ellos para preguntar quién tenía un documento específico.
Esto era un horror además de poco efectivo. Nos pidieron opinión para diseñar un sistema centralizado para compartir información: la idea inicial era construir un FTP que enviase mails automáticamente cuando alguien añadía un documento a una u otra carpeta, según una jerarquía que estaba siendo definida. Luego de algunas vueltas y no pocas conversaciones llegamos a algo diferente a lo que pedían inicialmente. ¿Por qué no crear un sistema de gestión de expedientes que se integre con otras herramientas que ya tenéis? No un FTP más organizado o e-mails automáticos. No un caballo más rápido, sino un coche.
La diferencia puede parecer sutil, pero conceptualmente es un salto importantísimo: las conversaciones con el cliente pasaron de pivotar sobre los nombres de las carpetas que debería tener el FTP centralizado a centrarse en cómo hacían las cosas, los fundamentos de sus procesos internos. En este caso, el resultado fue que no hicimos nada de lo que inicialmente se había pensado (FTP centralizado, envío de mails, etc) y, sin embargo, el proyecto es ahora fundamental en su día a día.

Análisis orientado a tarea

¿Qué es lo que nos llevó a determinar que existía una mejor solución? Creo que simplemente poner la mirada en cómo trabajaban y escuchar, no sólo dejar que el sonido entrase en las orejas. A partir de ahí, pensar un proceso para compartir información sobre la base de cómo hacían ellos las tareas y orientar la construcción de herramientas al soporte de ese proceso.
En ese momento no fuimos conscientes de que estábamos haciendo análisis orientado a la tarea. Supongo que llegamos a esa idea simplemente por ponerlos en la piel de los usuarios, por dedicarle un poco de cariño al proyecto. Desde luego no conocíamos «Understanding the job» de Christensen:

Ni todavía habíamos llegado a Ryan Singer y sus interfaces orientadas a la tarea, aunque poco después empezamos a escuchar lo que estaba diciendo este chico:

El análisis de la tarea en diseño de interacción

IxDesign_Matrix

A lo largo de mi carrera, creo que esta técnica ha sido uno de los aprendizajes que más impacto ha tenido en cómo enfoco mi trabajo y en las soluciones que propongo.
Es en este marco en que el estudio de las ideas de Bill Verplank cobran muchísima relevancia. Se me hace ahora más claro cómo encaja el análisis orientado a la tarea en el marco general y las distintas fases del proceso creativo, los outputs que debemos esperar de cada una de ellas.

Su librito sobre diseño de interacción ha resultado fabuloso como integrador de muchos conceptos que tenía sueltos. Entre otras cosas, me ha permitido clarificar también dónde encaja la metáfora de mapa VS ruta, que es un buen heurístico para ayudarte a pensar cómo el usuario va a interactuar con el producto.
La verdad es que sienta muy bien dedicar un tiempo a reflexionar sobre lo que uno hace y pararse a estudiar cómo lo hacen otros. Ayuda a clarificar ideas y eliminar lo superficial. Es como dedicar un tiempo a afilar el hacha antes de empezar a cortar árboles. Eres más productivo con un hacha afilada y te cuesta menos esfuerzo. Supongo que es también ahora, cuando uno pasa a ser consciente de cómo hace las cosas, en que empieza lo divertido. ¡Abróchense los cinturones!

Inversión y amortización en la selección tecnológica

Dependiendo del día y la hora, actúo como programador, dueño o CTO en una PYME. A lo largo de estos años, me he encontrado en varias ocasiones ante la situación de tener que seleccionar tecnología para un proyecto, compaginando los diferentes roles y perspectivas.

Poco a poco, he ido desarrollando «una intuición», una personalidad propia sobre la dirección que nos interesa a la hora de valorar las opciones tecnológicas. La selección tecnológica en una PYME es un proceso que va más allá de lo técnico, tiene componentes sociales, y también económicos. Estos últimos son los que quiero explorar con esta nueva serie con unos cuantos amigos. Se habla demasiado de los beneficios intrínsecos y universales a cada tecnología particular y muy poco de todo lo demás, que posiblemente tenga más influencia en el tipo de relaciones que una PYME puede generar con su entorno.

Inversión y amortización, lo nuevo y lo viejo

Durante la ejecución de un proyecto, van emergiendo ideas que permitirían reducir tiempos o abrir nuevas oportunidades de negocio a medida que el aprendizaje se consolida. Algunas de ellas tienen sentido y unos costes que te permiten ponerlas en marcha de inmediato; otras, requieren más tiempo o maduración. Aunque suelo ser muy comunicativo con estos aspectos (la comunicación es el oxígeno de una compañía con responsabilidades distribuidas como la nuestra) no es hasta que toca pensar un proyecto nuevo en que bajo esas ideas a la práctica y me pregunto: ¿qué es lo más efectivo que podemos hacer en este proyecto para mejorar nuestros procesos y productos? ¿hacia dónde se están moviendo las necesidades de nuestro mercado? ¿necesitamos cambiar algo drásticamente? Este proceso de evaluación continua requiere mantenerse actualizado y es muy necesario para que el cambio no te pille desprevenido, para evitar ahogarse si el mercado en que navegas naufraga:

«When heavily invested in a technology, you live in a memetic bubble, which also serves as an echo chamber. Bubbles created by vendors are particularly dangerous because you never hear honest appraisals from within the bubble. But the biggest danger of Bubble Living comes when it starts collapsing, which you never notice from the inside until it’s too late.»

En ese proceso de re-evaluación, hay ocasiones en que toca apostar por algo nuevo y soy consciente de lo que eso supone: estamos ante una inversión. Decidimos invertir porque la posibilidad de beneficios pesa más que los costes y riesgos. La promesa puede ser que nos ayudará a acceder a nuevos mercados, fortalecerá nuestra posición frente a la competencia o reducirá nuestros tiempos y costes de producción, entre otras (aunque éstas son las más habituales que me encontrado por el momento). No puedo negar que, como humano y programador, mi pasión por aprender cosas nuevas y «hacer las cosas bien» influye también en mis decisiones.

Sin embargo, noto que, con los años, mi impulso por asignarle a lo nuevo características positivas por defecto, es menor: soy más juicioso. Quiero pensar que he aprendido a valorar el esfuerzo que supone aprender algo nuevo hasta el punto de, no sólo ser productivo, sino poder ofrecer una alta calidad en mi trabajo. Por muy necesaria que sea la prospectiva y mantenerse actualizado, nuestra industria peca con asiduidad de confundirla con dejarse llevar de forma baladí por la novedad, aporte o no. En economía existe un concepto llamado amortización, que viene a decirnos que el valor de algo se extiende en el tiempo y, por lo tanto, va contra el beneficio sustituirlo mientras su valor no está agotado (no está amortizado), a no ser que lo nuevo aporte un valor netamente superior.

Hablar en estos términos de la selección tecnológica (inversión VS amortización) nos ayuda a enfocar los problema y buscar soluciones.

¿Es posible encontrar el equilibro entre las fuerzas?

Las decisiones tecnológicas no se toman en el vacío, hay un contexto previo, procesos y personas implicados. Necesitamos aprender a reflexionar sobre tecnología no por las cualidades intrínsecas y universales de la misma, sino por las interacciones entre el conjunto de fuerzas en juego. Necesitamos una microeconomía del software, una herramienta que nos ayude a evaluar el equilibro y nos oriente en la toma de decisiones.

En mi experiencia, el equilibro es frágil y complicado de predecir, pues incluye preguntas de difícil respuesta como: ¿cuándo un framework que hemos usado se puede considerar amortizado? ¿cuánto va a retrasar la entrega/proyecto el uso de esta nueva librería? ¿cuándo voy a percibir los beneficios de su implantación? ¿es sensato introducir Node en un equipo de 4 personas donde 3 de ellas no tienen conocimiento web ni javascript previo y el 80% de los proyectos que vas a realizar en los siguientes 2 años son aplicaciones de escritorio?

Pero aunque sea difícil la tarea, una vez sabes que estas fuerzas existen, son fácilmente reconocibles y pensar en clave de oposición entre ellas aporta un inmenso valor en la toma de decisiones. A partir de ese momento, has pasado de ser programador a convertirte en CTO: piensas la PYME como una unidad de producción y estás teniendo en cuenta no sólo tu proyecto o intereses personales sino la evolución de la empresa. Incluyes en tus análisis que, a las finales, esto va de ser rentable para dar de comer a los que la componen.

En esta encrucijada por encontrar el equilibrio, a lo largo de los años, he ido detectando ciertas variables que modulan la intensidad relativa de la inversión y amortización:

Experiencia del equipo

La historia de por qué Disqus usaba Backbone y Django como opción por defecto refleja el tipo de cosas que tienes que preguntarte. La cuestión clave es saber si, además de ti, hay alguien (en tu equipo directo o a salto de subcontratación) que pueda echarte una mano ahora o pueda recoger tu testigo a medio plazo. Si trabajas en una PYME seguramente vas a necesitarla más pronto que tarde ya que esto es como una comunidad donde, si bien hay distribución del trabajo, hay también mucho de pluriespecialismo y colaborar un poco en todo – bien por tamaño del equipo, bien por apurones.

Capacidad de adaptación del equipo

Relacionado con lo anterior, es esperable que la experiencia y capacidades de tu equipo estén alineadas con lo que vendes y produces. Un cambio supone un impacto, un tiempo de aprendizaje de otras capacidades, moverse hacia otras direcciones. El tiempo que le lleva a alguien llegar al punto de ser productivo ante un cambio es muy variable de persona a persona y tiene mucho que ver con su experiencia previa y su pasión por aprender. Algunas empresas lo pueden solucionar cambiando de equipo a golpe de talonario; las que nos definimos como democráticas y aspiramos a crecer horizontalmente, de manera orgánica, debemos tener en cuenta que el impacto del cambio en nuestros tiempos de producción y calidad del producto final no va a ser despreciable.

Acceso e integración de talento

Hoy en día, en España,  si te sales de Java y sus frameworks (Spring, Struts, Wicket) es probable que te encuentres con que los recién licenciados no conocen de qué estás hablando. En las escuelas de informática se está abusando de la concentración en torno a Java, probablemente por la promesa de oportunidades laborales en las «fábricas de software» (que por otra parte se ahorran tiempo de formación porque los nuevos ya vienen de casa aprendidos). En cuanto a gente con experiencia en una tecnología reciente (pongamos por caso Scala, Node), el coste de acceso a ese talento y el riesgo de que se vaya al poco tiempo puede ser prohibitivo para una PYME. Sin duda hay espacio entre tecnologías ampliamente conocidas y otras todavía minoritarias, la cuestión es saber que la decisión tiene impacto en tu capacidad de contratar talento y valorar en qué parte del espacio te conviene estar.

Mercado: oligopolios y efectos red

En ciertos mercados, las opciones tecnológicas tienden a la concentración. En mi caso -sistemas de información geográfica y web- en el stack tecnológico pesan mucho lenguajes como javascript, python y java, con esos lenguajes puedes hacer casi cualquier cosa: desde un plugin para una aplicación de escritorio a una web con servicios de geolocalización. Si buscas sinergias con otras empresas, necesitas integración con otros proyectos, quieres usar librerías existentes o simplemente reaprovechar conocimiento en este sector, conocer Ruby es menos valioso y te abrirá menos puertas que los 3 anteriores. Un economista puede reconocer fácilmente esta situación como efectos red del ecosistema (número de empresas participando, librerías existentes, disponibilidad de foros de consulta, etc). Los efectos red tienen más impacto en el éxito de una tecnología que su belleza o calidad técnica superior. Es la razón por la que PHP y Javascript ganaron la web a principio de siglo, a costa de Perl que tenía el dominio en los 90.

Nivel de indirección y reaprendizaje de la tecnología

Uno de los mayores costes del desarrollo de software es el re-aprendizaje. Al cambiar de tecnología no sólo se pierde código, sino también conocimiento. Apostar por una solución más cercana a los estándares -o con menos conocimiento específico, llamémosle magia- facilita que pierdas menos cada vez que te cambies, aunque puede ser más costoso al inicio ofrecer lo mismo que con otras soluciones con más magia. Por ejemplo, una tecnología como Backbone te habilita a usar los estándares (al final casi sólo te ofrece una manera de organizar tu código Javascript), sin embargo Angular o React te proponen el aprendizaje de una serie de idioms propios a cambio de la promesa de la rapidez de desarrollo.

Volatilidad y adaptación al cambio de la tecnología

Ligado a lo anterior, se puede decir que una opción tecnológica puede estar más preparada que otra para adaptarse al cambio. Una base de código que, por ejemplo, esté basada en Backbone es potencialmente más flexible a la hora de integrar novedades tecnológicas que otra que siga los idioms de React. Esta última tendrá que esperar a que en React se integren los cambios de los estándares o aparerezcan plugins que lo hagan – dependiendo del tamaño del ecosistema alrededor de React esto puede ser más rápido o más lento. Una situación de volatibilidad hace que el período de amortización de una tecnología pueda ser anormalmente corto, lo que afecta a tu capacidad de generar beneficio si tienes que cambiarla al poco tiempo de empezar a usarla. Pueden existir zonas del código y el proyecto con alta estabilidad (no hay ni se esperan novedades tecnológicas) mientras que otras tienen una alta inestabilidad. Lo importante es detectar dónde te interesa no casarte con nadie porque todo está en ebullición y  dónde es seguro además de recomendable hacerlo porque el período de amortización es estable y la reducción de costes es real, no sólo una promesa.

Amortización esperada de la tecnología

Esto tiene que ver con el cálculo de los beneficios esperados. Influyen cosas como lo que estimes que vas a trabajar con esa tecnología en el futuro (no es lo mismo que, durante los siguientes años, estimes un reparto de trabajo de 90% en productos web y 10% en proyectos móviles que un ratio de 60% para aplicaciones de escritorio y 40% en web). Si lo que esperas es crecer mucho en un área determinada, tendrás más espacio para amortizar la inversión porque tendrás más oportunidades de reutilizar el conocimiento y código que has hecho. El alcance de las inversiones tecnológicas deben ir acordes también con tus expectativas de negocio y evoluciones estratégicas.

Margen de inversión

En una PYME no es muy habitual poder dedicar 3 meses a realizar prototipos un poco complejos con varias tecnologías. Habitualmente los tiempos son muchos más reducidos y necesitas sacar trabajo adelante. Es importante que sepas el tiempo que tienes para equivocarte y salir del apuro cumpliendo con las entregas de un proyecto, porque eso va a ser principalmente tu margen de inversión. Aquí importa no sólo el tiempo de duración del proyecto, sino también la incertidumbre que lo rodea: estabilidad de los requisitos, conocimiento previo del dominio, confianza con el cliente para negociar reducciones de alcance o retrasos, etc. También influirá tu compromiso a la hora de solucionar los marrones donde te has metido. Por ejemplo, parece claro que el margen de inversión que tiene un proyecto de 1 mes con alta incertidumbre en cuanto a requisitos, es mucho menor que otro de 12 meses donde conoces perfectamente el dominio y los riesgos que existen.

En mi experiencia, estas variables modulan la intensidad de la inversión o amortización y, dependiendo de la elección en que te encuentres, unas pesan más que otras. Por ejemplo, a la hora de seleccionar un lenguaje y ecosistema para un nuevo proyecto, el mercado de referencia (y sus efectos red) así como la composición de tu equipo son 2 de las variables que me parecen más importantes. Sin embargo, a la hora de seleccionar una librería concreta, el nivel de indirección y volatilidad del ecosistema suele tener más peso en mis decisiones.

A medida que uno avanza y toma experiencia se van haciendo más claras éstas y otras variables, aparecen nuevas, otras se reinterpretan. Lo importante es reconocer las fuerzas, no dejarse llevar por los análisis universalistas y pensar el impacto de las decisiones desde un contexto determinado: el tuyo.

Diseño y testeabilidad

Todo programador que lleve un tiempo en esto, ha vivido debates sobre «arquitecturas» o «patrones de diseño». Dentro de la serie que he iniciado para hablar de desarrollo de software en una PYME, creo que estos debates tienen un encaje fundamental porque una vez seleccionas tecnología tienes que darle forma de alguna manera. Y esa manera es el «diseño» o «arquitectura» de tu producto.

El «buen diseño»

Lo primero que conviene recordar es que la reducción de los tiempos de producción y mayor calidad de producto es el camino de una PYME para ofrecer el máximo valor posible al cliente. En el mercado, eso te pone en una situación favorable con respecto a tu competencia. Definiremos, pues, como «buen diseño», aquel que se pone al servicio de la producción, que permite aumentar la calidad y reducir los tiempos de desarrollo.

Podemos continuar y definirlo como flexible y mantenible, bello y que hace sentirse orgulloso al que lo crea, etc. Pero el problema no es tanto definirlo, sobre lo que existe mucha literatura, sino cómo se llega a él y cómo se mantiene a lo largo del tiempo. Porque tenemos que reconocer que no es fácil y que existen varios problemas. Para empezar, no existe un diseño universal válido sino que hay tantos como contextos, que las personas, además, insisten en tener diferentes opiniones sobre qué es un «buen diseño» y que ambas cosas se reflejan en el código – lo que fácilmente puede convertir tu producto en una torre de babel ininteligible si no se construye una visión común. Tenemos, además, estructuras de comunicación disfuncionales que provocan diseños sub-óptimos, deuda técnica y requisitos cambiantes que introducen variantes a lo largo del tiempo, rotación de personas en los equipos y distintos niveles de experiencia que dificulta la transmisión de ideas, etc. Es decir, el software, su diseño, se ve afectado por las fuerzas humanas y organizacionales. ¿Cómo podemos ponerlo a salvo? ¿Cómo asegurarnos de que las fuerzas están en equilibrio y el diseño sirve a nuestros objetivos?

Necesitamos salvaguardas que nos permitan calibrar qué es un «buen diseño» y controlar su degradación a lo largo del tiempo, herramientas que nos ayuden a caminar hacia a él y nos orienten.

Los tests como salvaguardas

Michael Feathers, en su libro «Working effectively with legacy code» desarrolla la idea de cómo trabajar con software que está degradado. Cómo, partiendo de código degradado, se puede conseguir un «buen diseño» a partir de las restricciones habituales en el día a día (tiempos limitados, código con altas dependencias, etc). Es un libro por ello interesantísimo porque te cuenta ciertas maneras de cómo llegar a ese buen diseño. Y su principal herramienta son los tests:

«When you start to try pull out individual classes for unit testing, often you have to break a lot of dependencies. Interestingly enough, you often have a lot of work to do, regardless of how “good” the design is. Pulling classes out of existing projects for testing really changes your idea of what “good” is with regard to design. It also leads you to think of software in a completely different way.»

Empatizo por completo con su visión. Sobre los tests hay poco que decir: tener o no tener, that’s the question. Porque tenerlos afecta a la producción a varios niveles:

  • El primer efecto y más obvio es que, tenerlos, reduce los tiempos más inciertos y difíciles de estimar en proyectos de software: el testeo manual que hay que hacer en cada versión y el bugfixing. En gran medida, estos tiempos son los que suelen determinar que un proyecto sea o no rentable.
  • Otro efecto un poco más indirecto es que, para desarrollar software testeable, necesitamos dividirlo en trocitos, evitar y romper las dependencias. Es decir, estamos en la dirección de desarrollar software reutilizable, reducir la complejidad.
  • Quizás un poco más sutiles sean los efectos a nivel personal, pero no menos importantes. Por un lado, aportan seguridad y confianza en tu trabajo a posteriori ya que tienes algo objetivo y automático que te dice que funciona. Pero es que además, durante el proceso, tener feedback continuo te ayuda a enfocar tu trabajo y a mantener tu moral alta a base de pequeñas victorias cotidianas. Y la moral, en tareas creativas, es un factor clave en la productividad.

Conclusiones

Tests y diseño van de la mano. Una vez has sentido sus efectos, tu visión cambia. Aprendes que un buen diseño es un diseño testeable. Porque eso es lo que te va a permitir reducir tiempos de producción y aumentar la calidad de lo que ofreces, ganarte la vida desarrollando software de un modo sostenible, que, al final, es de lo que va todo esto.

Arquitecturas para la participación

Este post cierra la serie que inicié hace unos meses sobre desarrollo de software en una PYME. En el primer post, escribría sobre cómo seleccionar tecnología; en el segundo, sobre un mecanismo para objetivar el diseño y reducir los costes de producción. En este último escribiré sobre cómo la organización del código que escribes habilita relaciones con otros.

Programar es una comunicación entre personas

«Programs must be written for people to read, and only incidentally for machines to execute»

Esta frase extraída del prólogo del mítico SICP es una de las perlas que, entre los hackers, define el buen hacer de la profesión y que pone sobre la mesa toda una declaración de intenciones por parte de Abelson y Sussman: la programación es un nuevo medio de comunicación y expresión de ideas entre personas. De este enfoque se deriva que lo fundamental a la hora escribir programas de software es hacerlo de tal manera que nuestros limitados cerebros puedan navegar rápidamente entre los múltiples detalles, con sus distintos niveles de complejidad.

Al escribir código, un primer nivel de comunicación se daría entre programadores (con otros o con nosotros mismos dentro de unos meses). La buena o mala comunicación de las ideas a través del código tendría un impacto económico que se observaría en los tiempos necesarios para la adaptación, mantenimiento y aprendizaje de un programa. Entender un programa es un acto intelectual donde entra en juego la experiencia previa, la capacidad de relación de ideas y la compresión lectora, pero también la buena maña del que lo haya escrito para hacerlo de un modo inteligible. Al igual que un ensayo, un programa requiere cohesión interna y ritmo para ser entendible.

Un segundo nivel de comunicación se daría entre programadores y analistas del dominio y/o clientes. Ese tipo de conversaciones modela cómo se comporta el sistema y se transmiten al código en forma de estructuras de datos y algoritmos.  Un programa no es más que la declaración de un proceso que tiene entradas y salidas.

El hecho de que el software refleje estas relaciones sociales es conocido desde hace décadas y cristaliza en una de las más populares leyes de la programación, la ley de Conway:

«Any organization that designs a system will produce a design whose structure is a copy of the organization’s communication structure.»

Es decir, las conversaciones, grupos y jerarquías existentes en el proyecto se trasladarán al código de manera inevitable. La arquitectura reflejará tu estructura de comunicación y poder, determinando el tipo de relaciones que puedes tener con tu entorno. Toda una profecía ciberpunk.

Pero … ¿cómo habilita o dificulta relaciones la arquitectura?

Una PYME pequeña funciona como una comunidad: aunque existen roles y división de responsabilidades (diseñador, programador, administrador de sistemas, analista), hay mucho de pluriespecialismo. Además, por el propio tamaño de empresa, en muchas ocasiones existen proyectos que se realizan con otros equipos. Existen arquitecturas o maneras de modularizar el código que te permiten que esa división del trabajo sea más efectiva. Veamos algunos ejemplos:
Diseño orientado al dominio

La programación es fundamentalmente la transcripción de las conversaciones entre programadores y analistas. Es necesario tener un un lenguaje común y existir entendimiento entre ambos para que la cosa salga bien. Una de las prácticas que más me ha ayudado a organizar el código es el diseño orientado al dominio, es decir: organizar el código en torno a la interacción de las entidades que se definen en la conversación analista-programador. Aunque parezca una obviedad, no lo es, tiene sus trampas y se hace menos de lo que parece. El impacto de esta práctica deriva de cómo facilita las conversaciones y el entendimiento del programa.

Separación de API e interfaz

Esta técnica, conocida ya por los pioneros, ha retomado fuerza en la era de la web ubicua y la arquitectura REST. Con este mecanismo de modularización, el API define el acceso a datos y acciones que permiten usar el sistema. El interfaz es un mero usuario del API. Además de beneficios técnicos, esta frontera tiene beneficios sociales: facilita una división del trabajo en aspectos muy distintos de la aplicación, que requieren conocimientos, técnicas y herramientas diferentes. Esto permite que la colaboración diseñador-programador sea más fluida.

Hay 2 ejemplos que ilustran muy bien mi experiencia. En ciertos proyectos donde creamos formularios para la introducción de datos con una aplicación de escritorio, aplicar este principio nos ha permitido que nuestros analistas (repito: analistas, no programadores ni diseñadores) hayan diseñado por sí mismos los formularios que luego los programadores integran en la aplicación. En otros proyectos, hemos contratado a empresas para que nos ayudasen a crear un API mientras nosotros nos centrábamos en el diseño de la interfaz (y viceversa). Ambas situaciones serían muy complejas de delegar (o casi imposibles) si no hubiésemos hecho un uso intensivo de este principio a la hora de desarrollar el producto.

Creación de plugins o módulos

Otra manera muy evidente de crear espacios para la colaboración es permitir añadir nuevas funcionalidades a tu software mediante la creación de plugins o módulos. Este tipo de arquitectura minimiza la barrera de entrada para que nuevos colaboradores puedan ser productivos muy pronto, ya que no necesitan conocer todo el proyecto antes de incluir una funcionalidad, sino que les basta con conocer sólo lo que necesitan.

En nuestra experiencia colaborando con un proyecto empezamos por el desarrollo de pequeñas extensiones o plugins con funcionalidades limitadas. Pasados unos meses, nos sentimos cómodos y con conocimiento suficientes de ciertas partes internas de la aplicación como para modificarlas y enviar mejoras. Los primeros plugins fueron exploratorios, nos permitieron familiarizarnos con el código y el producto; una vez confiamos, nos lanzamos a cosas mayores. Fue precisamente un aspecto técnico (la creación de plugins) el que nos habilitó para iniciar una relación comercial con el proyecto: de no existir esa posibilidad al principio, se nos hubiese hecho muy difícil como PYME invertir todo el tiempo necesario para entender un proyecto tan grande.

Estos son algunos ejemplos de cómo la arquitectura habilita o impide relaciones, pero existen otros miles de pequeños detalles. La modularización del código es fractal, influye en todas las capas de la aplicación.

Conclusión

El programador es, principalmente, un organizador de ideas y un ensayista. Necesita cierta capacidad lógica para analizar y diseñar un sistema, pero también para organizarlo de manera que habilite buenas conversaciones y una división del trabajo efectiva. Necesita entender a las personas con las que trabaja.
Es por ello que no me parece casual que Kent Beck, el gran recuperar de ideas de nuestra generación, apuntase hace no mucho que uno de los factores con más impacto a la hora de ser un buen programador es la empatía.

the *craft* of programming begins with empathy, not formatting or languages or tools or algorithms or data structures

— Kent Beck (@KentBeck) febrero 13, 2015