viernes, diciembre 26, 2014

Pérdidos en el MVP (Minimum Viable Product)

Esta va a ser la historia de como una buena idea se complica lo suficiente como para no llevarse a cabo en el corto plazo, y como alguien sabe de ella y la  ejecuta con lo mínimo, ganando la puesta de bandera.

Hace algún tiempo atrás  participé de los procesos creativos de un emprendimiento. Bando buscaba integrar salas de ensayo con bandas, y si bien es cierto el mercado al que apuntaba es sumamente acotado, la idea podía dar cabida a otros desarrollos. Finalmente me excluí del proyecto (otra historia).

Pocas semanas atrás mi gran amigo Gastón me comenta sobre BandAid, una aplicación para Android que es básicamente un directorio de salas de ensayo y tiendas de música en Santiago de Chile. Claramente al menos algo deben haber sabido de Bando, cosa que por lo demás no era demasiado difícil puesto que se hizo una campaña de publicidad bastante agresiva.


¿Dónde falló Bando y tuvo éxito BandAid?

El MVP de Bando, bajo mi perspectiva de informático, no era tan MVP. Buscaba cubrir demasiados requerimientos, siendo que para empezar bastaba resolver el tema de un directorio de salas de ensayo.

En este sentido me estoy volviendo un acérrimo partidario de la filosofía del lanzamiento temprano (release early). Lanzas un producto que resuelve puntualmente y de buena manera UNA necesidad (requerimiento), y SOLAMENTE UNA, vas recibiendo feedback y te obligas a seguir trabajando en tu producto. Quizás añadiendo nuevas características (features no bugs), y así tu lanzamiento temprano es la puesta de bandera, fuiste el primero.

Siendo el primero, lo primero (valga la redundancia) es que no van a decir que eres copia de otros.
Una vez que tu bola de nieve gana momentum, ya nada podrá detenerte, salvo cuando se termina la pendiente de la montaña, pero a esas alturas ya tendrá volumen, y habrá aplastado bastante en su camino.

El Mínimo Producto Viable (MVP)

Supuestamente es lo mínimo que esperas de tu producto. El problema radica precisamente en eso, es lo que TU esperas de TU producto, y ahí se pierde inmediatamente toda objetividad. Desde dentro uno tiende a esperar demasiado, como mínimo.

Los chicos de 37 Signals, los autores del libro Getting real y dueños de Basecamp, plantean precisamente el hacer menos para lograr más.

Con Basecamp vieron la complejidad de las herramientas de gestión de proyectos, las interpretaron como una seria deficiencia y decidieron simplificar al máximo la herramienta, y de paso el proceso.
Su motto es resolver UNA sola tarea, de manera sencilla, pero hacerlo de la mejor manera posible. La vida actual va tan rápido que no hay tiempo para complicaciones.

Entonces para definir tu MVP pregúntate:
  • ¿Qué tan simple es mi idea?
  • ¿Qué tan simple es llevarla a cabo?
  • ¿Qué tan simple es escalarla?

Y eso pasando por alto las capacidades de tu equipo, porque tu equipo puede ser sumamente capaz, y puede resolver problemas infinitamente más complejos. Todo radica en la simplicidad.

Y si es simple, sobretodo tratándose de sistemas de información, hablará por si  solo, será intuitivo de usar, será preferible a otros sistemas similares y más complicados.

Mi experiencia inmediata

Mi esposa me planteó su necesidad de hacer un listado de tareas para organizar las actividades de su día a día. Recordé el plugin Full Calendar de jQuery, le pregunté si algo así le serviría y me dijo que sería genial tener algo así.

Ahí tengo la idea de una aplicación.
Sin duda hay miles de productos similares, mucho más maduros y completos, y probablemente con infinito más tiempo dedicado que  lo que quiero hacer.

Mi checklist

  1. La idea va a comenzar en eso un calendario y un formulario simple para agregar tareas, así de simple y no más que eso. 
  2. Cuando resuelva lo primero, recién me voy a preocupar de agregar extras. Por cierto el diseño preliminar tiene que ser aprobado por mi cliente.
  3. Evaluar si se van a agregar extras. probablemente ni siquiera sea necesario.
Si complico mi idea lo más seguro es que ni siquiera la lleve a cabo, y sacando cuentas alegres es más menos una tarde de trabajo, lo que tampoco es tanto.
Mínimo esfuerzo para dejar contenta a tu esposa, créanme, eso no tiene precio :D

jueves, diciembre 25, 2014

Lo que aprendí de L1bera

Hace algunas semanas atrás respondí a una invitación abierta de mi amigo y lider de la banda chilena L1bera, para asistir a un ensayo de su banda. Debo confesar que el estilo de L1bera no es precisamente de mi devoción, pero la experiencia fue enrriquecedora.

http://www.l1.cl/descargas/discos/R3VOLUC1ON.rar


L1bera es una banda cuyo estilo clasifico (probablemente equivocadamente) entre el aggro y el nu-metal, pero de la vieja escuela, guitarras y ritmos agresivos, equilibradamente mezclados con secuencias, y con una voz más melódica nada gutural. Influencias  peligrosamente marcadas, donde si no fuera por el arte que pone cada integrante de la banda uno tendría la tendencia a decir que son una copia de Limp Biskit pero en español.

Durante el ensayo traté de pasar lo más desapercibido posible, de modo de no interferir en los procesos creativos propios de la banda, más todavía cuando L1bera está en plena preparación de nuevo material.

Debo reconocere que fue una muy grata experiencia, aún cuando el ensayo se extendió bastante más de lo que tenía presupuestado, pude ser testigo de la gestación de un nuevo tema, que según las palabras de Gastón está quedando increíble.

https://www.facebook.com/AGUEROL1


Gastón demostró un liderazgo innato, lo que no se debe confundir con autoritarismo. Expone sus ideas frente a la banda de una manera clara, de modo que todo las vayan trabajando por pedazos hasta que consiguen que el conjunto sea una pieza más del rompecabezas, con un rol específico, y que calce perfectamente al lado de las otras.
En ese sentido me llamó la atención como los 2 integrantes encargados de la parte rítmica, bajista y baterista, consiguen una comunicación que va mucho más allá de las palabras, y como "sin  querer" se aferran a lo que han definido inicialmente, matizándolo para conseguir la aprobación final. Así partieron con una rítmica muy "matemática", escapándose un poco de la línea de composición de la banda, y terminaron (en el ensayo) con la misma rítmica inicial, pero de alguna manera matizada acorde a lo que voy a denominar "requerimiento inicial".

Aplicado al desarrollo de software, que es la línea donde me muevo, Gastón es el buen jefe de proyectos, que lidera a un equipo de desarrollo, les expone sus ideas y requerimientos, y a veces busca imponer algunas posturas, basadas en las fórmulas que sabe que funcionan.
Por otro lado está el resto de la banda, que sería el equipo de desarrollo. Ellos acogen las ideas presentadas inicialmente, y contribuyen con lo propio, a veces difiriendo con el planteamiento inicial, pero enrriqueciendo el producto final. En este sentido, y lo veo a diario, la experiencia de los desarrolladores puede escaparse de las fórmulas conocidas, y la implementación final puede  resultar mucho mejor que la tradicional. Al respecto, también estan todos los casos y variaciones imaginables, la fauna del desarrollo de software da para muchas sorpresas.

Nota aparte merece el nuevo guitarrista de la banda. por lo que vi viene de una "escuela" musical mucho más técnica, y durante el ensayo al que asistí pude notar como aún se estaba adaptando a un equipo que ya lleva tiempo trabajando juntos. Es como el "estudiante en práctica con posibilidad de contrato" en las empresas, desde mi percepción sentí como aún necesitaba un guía, sin embargo el factor de caos que induce renueva al equipo.

Fue un honor ser testigo presencial de un proceso creativo diferente a los que estoy acostumbrado, y por ello quiero agradecer a Gastón y a todos los integrantes de L1bera por esta oportunidad única.

El Kame Hame Ha del marketing

En estricto rigor Kame Hame Ha no es exactamente el acrónimo que aplica a lo que voy a exponer, pero imagino que ya que estás aquí, no te vas a quedar con la curiosidad de que quise decir.

Hace algunas semanas regresaba a mi casa desde el trabajo en bicicleta, y me interceptó un chico para promover servicios de asistencia en ruta para ciclistas. La idea del grupo AER-ciclistas (por lo que entiendo en proceso de cambio de nombre ya que se confunden con AER que es otro grupo que lleva varios años trabajando ) es que si vas en tu bicicleta y sufres de un desperfecto en ruta, te comunicas con ellos y te pueden asistir para que no quedes tirado. Ideal para pinchazos, cortes de cadena, frenos o desperfectos digamos "menores".

Cuando el chico se acercó a mi y me contó lo primero que le dije fue "Ah, como BC-Help, pero ¿mejor?", a lo que, trás dudar un poco, replicó "Sí, pero más barato..." 
BC-Help es una tienda y taller de bicicletas, cuya principal característica además de la excelente atención es que te pasan una bicicleta de reemplazo mientras tienen la tuya en reparaciones. Personalmente he utilizado ese servicio en más de una oportunidad y han salvado mis semanas (cuento aparte es que evito a toda costa desplazarme por la ciudad utilizando otros medios de transporte que no sean mi bicicleta).

En el camino me fui pensando en donde está el problema de ese sistema de promoción y llegué a lo que voy a denominar el Kame Hame Ha del marketing.
(Insisto que no es exactamente el acrónimo, pero de seguro se van a acordar con Kame Hame Ha)



Conoce tu negocio - Know your Business

Independiente de la idea, producto o servicio que quieres promover, tienes que mostrar que sabes de que estás hablando. Una muestra mínima respecto a lo que ya existe, convence a tu potencial cliente, genera una necesidad, vende tu producto/servicio/idea ya que ustedes son las personas precisas, quienes más saben del tema. Y preocupate de saber del tema y no vender humo.

En el caso del chico de AER-ciclistas si se hubiera acercado quizás con un comentario técnico, una observación o incluso una consulta sobre mi bicicleta (cuyas ruedas sólidas Tannus dan para hacer al menos una consulta), hubiera capturado mi atención de mejor manera. Incluso hubiera cambiado mi disposición para conversar con él.

Conoce a tus clientes/mercado - Know you Market

¿A quién, o incluso adonde, apuntas con tu idea/producto/servicio? Es necesario tener una visión objetiva de hacia dónde quieres enfocar tus esfuerzos. Y no es solamente un tema de cuál es tu mercado objetivo, sino también relacionado con la localización geográfica, y incluso con la idiosincracia cultural inmediata que recibe tu oferta.
Por ejemplo si tu negocio es la venta de pedales boutique para  guitarras o bajos, ese mercado es mucho menor en Chile que en USA (debería decir derechamente el extranjero).
Si tu idea apunta a las bandas de música locales, o a la distribución de música por Internet, y pretendes tener un retorno de inversión en el mediano plazo, no puede no considerar factores como por ejemplo cuántos usuarios pagan por aplicaciones para dispositivos móviles, o cuántos pagan por descargar música.

Claramente siempre es una apuesta, SIEMPRE HAY RIESGO (con maýusculas para que no se nos olvide), sin embargo es mucho mejor apostar sobre mejores probabilidades.

Siguiendo con el ejemplo, ¿quiénes necesitan ayuda en ruta? ¿aquel ciclista equipado con la bicicleta toda embarrada o la niña indefensa que no se atreve a pedalear por la calzada? No es sano disparar tus balas al aire a ver si cae un pato.


Conoce a tu enemigo - Know your Enemy


Tienes una excelente idea, ¿sabes si existe en el mercado algo similar? ¿conoces o sabes de tu competencia? ¿puedes competir contra ella? Tu competencia es tu enemigo, tu "némesis". Ofrecen lo mismo, o algo muy parecido, o bien apuntan hacia el mismo mercado.
La única manera de vencer a tu enemigo es conocer sus fortalezas y sus debilidades. ¿Qué puedo ofrecer que mi competencia no pueda/no tenga?
Puedes apuntar al mismo segmento de mercado que otros, tener una propuesta de productos o servicios muy similar, pero de alguna manera hay que saber marcar una diferencia que haga que los clientes te prefieran a ti y no a tu competencia, incluso lanzar tu producto antes (ya me referiré a esto en otro articulo).
Por ejemplo Apple no tiene el monopolio sobre los dispositivos de audio portatil, sin embargo la calidad de sus productos establece su hegemonía muy por sobre la competencia.

Extrapolen estas preguntas a gusto:
  • ¿Cuánto sabe AER-ciclistas de BC-Help
  • ¿Pueden competir con ellos? 
  • ¿Ofrecen algo diferente/complementario/ preferible a BC-Help?

Una lectura al Arte de la Guerra de Sun Tzu pareciera ser una buena recomendación.

Finalmente no deben olvidar ser objetivos, desde dentro es muy fácil ver la mediocridad como algo imponente. Pónganse el traje de sepultureros y estén dispuestos a echar tierra sobre sus propias ideas, no por el afán de la autocrítica, sino para fortalecer los propios puntos flacos.

Nota: El acrónimo en inglés seía KBKMKE (kay bee kay em kee), pero deben reconocer que Kame Hame Ha suena bastante mejor :)

miércoles, septiembre 24, 2014

Metodologías de desarrollo ¿Ser o no ser?, he ahí la cuestión

Este mes comencé una "nueva aventura/desafío laboral" en otra empresa. Viniendo de una modalidad de trabajo bastante salvaje, llegar a una empresa donde el uso de metodologías de desarrollo es intenso ha sido un cambio no menor. La experiencia ha sido bastante diferente a lo acostumbrado.

En mis trabajos anteriores si bien nos preocupábamos de una u otra manera de llevar un control de versiones, y llevar algún registro de actividades, todo el desarrollo se realizó de manera "salvaje". Salvaje en el sentido que más que el control sobre las actividades a realizar, lo que importa, y casi lo único que importa, es cumplir con las entregas finales de código (y no es que con metodologías más estrictas esto sea menos importante). Dicho en fácil, estuve desarrollando "a lo brutito" mucho mucho tiempo. El objetivo era cumplir si o si.

Metodologías

En esta empresa, muy ligado al alto nivel de los profesionales del equipo con el que debo trabajar, así como también la envergadura del proyecto en curso, la planificación y las metodologías son vitales:
  • Se realiza una planificación para la semana. Un conjunto de tareas que debiera estar resuelto en un plazo dado. La fecha tope normalmente no debiera exceder  de una semana de trabajo (5 días).
  • Cada mañana se realiza una "breve" (a veces no tan breve) reunión, a priori no más de 3 minutos por persona. Todos de pie debemos contar que hicimos en la jornada anterior, y cuál es nuestra planificación para el día de hoy. Se deben levantar las alertas necesarias  sobre aquello que pueda dificultar el desarrollo.
  • Cada viernes, idealmente en la mañana, se realiza una sesión de demo en la que se presenta al equipo algún resultado visible de las actividades realizadas en la semana.
  • Las actividades se ordenan en un tablero Kanban en el cual cada tarea se va moviendo de columna conforme al estado de la misma. Las columnas son:
    • Por hacer
    • En desarrollo
    • Detenido
    • Resuelto
    • Cerrado
  • Cada bloque de código tiene que contar con su correspondiente set de prueba. El Test Driven Development (TDD) amerita un artículo aparte (próximamente en este mismo canal).
Uno de los focos principales es la autogestión del equipo, por lo que cada integrante hace sus propias estimaciones de tiempo.
Y el nivel de control sobre el equipo de desarrollo es claro, siempre sabes que están haciendo todos.

Lo positivo

  • El equipo tiene una visión general de todo lo que está pasando. Se lo involucra en las actividades de la empresa, lo que SIEMPRE es bueno.
  • Se logra un nivel de orden para las actividades de cada integrante del equipo.
  • Se puede dimensionar el costo en tiempo para el desarrollo de un proyecto.
  • Se van afinando, progresivamente, los procesos de desarrollo.

Lo no tan bueno (desde la humilde perspectiva del autor)

Mi gran reparo respecto a la aplicación de estas metodologías apunta hacia el tiempo.
Hacer una reunión diaria, de pie, en un equipo de más de 5 personas puede tomar por lo bajo 30 minutos. Similarmente hacer una sesión de sesiones de demo, podría extenderse al orden de una hora.

En relación al registro de actividades y atenerse a las directrices que se definan incluso para los comentarios al subir código a un repositorio de versiones tampoco es  una tarea directa.

Y sobre los sets de pruebas, estos deben considerarse como un desarrollo anexo, que se suma al tiempo normal de desarrollo. Suele suceder que la detección y corrección de errores (bugs) puede resultar muy rápida, sin embargo la construcción de los set de pruebas muchas veces puede demorar bastante, y muchas veces no tienes como dimensionarlo de manera adecuada.

Tengo cierta claridad sobre la duración de los períodos reales de productividad diaria, habitualmente no más de 5 o 6 horas en una jornada de 8 horas, sin embargo contar con un hora menos para resolver mis tareas planificadas (y me refiero exclusivamente a mi experiencia) pesa.
En un trabajo anterior mi jefe decidió involucrarme en reuniones con cliente, a veces 2 horas al día. Paralelamente yo tenía asignadas ciertas actividades de desarrollo, con fechas de entrega planificadas. Esos días por fuerza tuve que recuperar las horas que literalmente perdí por estar metido en reuniones.

¿Ser o no ser? (o ¿cuándo usar metodologías?)

La respuesta debiera ser siempre. Debiera ser...
Desde mi aún inexperto punto de vista, como en muchos otros casos, la respuesta será un gran depende. Las ventajas son bastante claras sobre no usar metodologías. Sin embargo, su uso estará definido desde la misma filosofía de la empresa hasta el tipo de proyectos que se está desarrollando.

  • Tratar de imponer el uso de metodologías en una empresa que ha sobrevivido en estado salvaje puede tener un costo más alto que el beneficio en el corto y mediano plazo tras incorporarlas. Hay empresas que simplemente no valoran hacer las cosas bien, basta con hacerlas (tristemente las hay...).
  • En proyectos "pequeños" desarrollados por ejercitos de un solo hombre es discutible (y sólo discutible) si vale la pena incluir el desgaste natural asociado a incorporar metodologías.

Personalmente creo que la decisión pasa por la apreciación que tenga cada lider de desarrollo respecto al recurso tiempo, y de que manera puede hacer mejor gestión de este.
Pero sí, hay mucha ganancia en usar metodologías, sólo hay que encontrar la combinación correcta, en la medida que civilice un poco los procesos de desarrollo

domingo, septiembre 21, 2014

¿Qué tan frágil es tu organización?

Hace aproximadamente un mes atrás conversaba con mi ahora ex-jefe sobre que tan frágil es una organización. Básicamente porque mi rol en la empresa tenía cada vez más responsabilidades, y en caso de irme reemplazarme no sería tan sencillo. Hoy estoy trabajando en otra empresa, y créanme que la últimas semanas en mi antiguo trabajo fueron intensas.

Un artículo atrás hablaba del costo de la especialización, y la importancia de poder desempeñarse como un profesional versátil (busquen por fullstack developer para más referencias al respecto).
Si bien es cierto un fullstack developer resulta muy valioso para la organización, es también un riesgo, tan grande como su valor como profesional, puesto que inevitablemente habrá muchas tareas que le serán confiadas. Muchas veces, por no decir la mayoría, este tipo de profesional será el único quien se puede hacer cargo de muchas de las ya mencionadas tareas, o bien será el único que las puede resolver de manera rápida y eficiente.

Cuando se dió esta conversación con mi antiguo jefe, me señaló que si yo me iba, le sería muy difícil encontrar a alguien que pudiera cubrir mi posición. Similarmente si se iba otro compañero que se ha involucrado más en actividades de gestión que de desarrollo, la empresa se tambalea.
Paradojalmente unas semanas después recibí una oferta de aquellas que no esperas que se repitan, y la acepté. Es complejo ver como la empresa en la que has trabajado tiene que empezar a considerar el plan B para todas las actividades en las que estabas involucrado.

¿Ustedes tiene un plan B en caso de?

¿Qué tan frágil es tu organización?

Habitualmente se dice que una organización es tan fuerte como su eslabón más débil, pero ¿qué tan frágil es?
La fragilidad de una organización, empresa, e incluso emprendimientos ligados al desarrollo viene dada por cuántos son los soportes que sostienen las actividades clave/sensibles/de vital importancia, y cuanto es el riesgo que se debe asumir si alguno de estos pilares ya no está en el equipo.

Por ejemplo: Un emprendimiento cuyo norte es entregar un producto de software no debiera depender de una sola persona para hacerse cargo del desarrollo (o de la parte TI si quieren ampliar el concepto). Si esta persona decidiera no seguir, si no hay como reemplazar sus experticias, es probable que tengan que replantear el emprendimiento en si.

Si miramos a las empresas como el juego de la Yenga, la fragilidad podría verse como  cuantos palitos puedes sacar antes que la torre de derrumbe. Mejor aún, dependerá además de que tan abajo o arriba estén los palitos que sacas (obviando el hecho que una torre no representa precisamente una pirámide organizacional).

Y claramente hay muchísimos otros factores que influyen.

viernes, agosto 15, 2014

El costo de la especialización

A principio de mes el equipo sufrió una baja. Un compañero que habían contratado por su experticia en Java optaba por una mucho mejor oportunidad laboral. Esto me hizo pensar, para bien y para mal no tan bién, en el costo real de la especialización.

Para proteger la identidad de los inocentes, denominaré M a este  ex-compañero.
M fue contratado por su experticia en Java, además de cierta experiencia en el área de salud. Lo entrevistó mi jefe. Pasaron aproximadamente 3 meses antes que M pudiera dedicarse a desarrollar en Java, los primeros meses fue necesario que colaborara en tareas de análisis y documentación, y que apoyara ciertos temas de base de datos.

M es un especialista en Java, particularmente en el framework Spring. Sus conocimientos en el contexto teórico son destacables. Y sería, M SABE Java y Spring. El resto de las áreas no le resultan desconocidas, sin embargo al no ser su especialidad, delegarle cualquier tarea constituía un riesgo de tener que revisar exhaustivamente el trabajo, o incluso hacerlo de nuevo.

OK, estamos claros que 3 meses fuera de tu zona de confort  pueden desmotivar a cualquiera, pero independiente de eso, por sobre todas las cosas debes ser profesional. En el peor caso, que tu disconformidad no se note, o bien conversarlo con la jefatura.

¿Qué tiene que  ver esta historia con el costo de la especialidad?

M es un especialista, y lo fue en un equipo pequeño. En un equipo pequeño ser un especialista tiene un costo muy alto (para bien y para mal no tan bien). Un equipo pequeño requiere profesionales versátiles, que puedan desempeñarse de buena manera en cualquier rol que se les asigne. En este caso, esperé mucho más de M, más que  únicamente su especialidad, y aún en su experticia.
Esto es un costo no despreciable para un profesional .

Su partida dejó al equipo sin un especialista al que se podían delegar tareas muy precisas, y se podía esperar que se resolvieran de buena manera.
Esto es un costo no despreciable para una empresa.

En una empresa con un equipo más grande es esperable tener múltiples especialistas, por lo que la versatilidad, se bien se agradece, puede no ser estrictamente necesaria.

¿Es bueno convertirse en un especialista?


Tratando de ser objetivo, la respuesta es un gran depende.

Siempre será bueno desarrollar experticia en un área. De hecho haciendo una introspección, todos nosotros dominamos ciertas materias mucho mejor que otras.

Por otro lado, siempre será bueno manejar, conocer, o simplemente defenderse en varias materias, sin necesariamente ser un experto. Ser versátil entrega una visión más amplia para enfocar los problemas (en general, no solamente en informática).
Claro que, al igual que los jugadores de fútbol, difícilmente habrá uno que juegue bien en todas las posiciones, pero nuevamente al igual que los jugadores de fútbol, los entrenadores del equipo lo agradecen, sobretodo cuando otro jugador falla.

También dependerá del tipo de equipo en el que se desea trabajar, o hacer carrera, el tamaño de la empresa u organización, y cual es su proyección profesional.
Un especialista por fuerza requiere de un equipo que lo complemente. Alguien demasiado versátil puede fácilmente transformarse en un "ejército de un sólo hombre", lo que, por conocimiento de causa y propia experiencia, bajo ninguna perspectiva es saludable.

Lo más importante, independiente del camino que decidan seguir, especialista o no, no traten de engañarse con títulos, experticias, o especialidades que no ejercieron. El papel, los currículum vitae y LinkedIn aguantan mucho, pero siempre hay alguien que verifica si realmente fueron un Arquitecto Java en su trabajo anterior.

martes, julio 01, 2014

AngularJS Case & accent insensitive filter

Siguiendo con AngularJS, requería de un filtro que me permitiera rescatar objetos desde un arreglo, pero con la particularidad de ignorar capitalización y caracteres especiales. Como no encontré nada terminé haciendo mi propio filtro, que comparto con los honorables lectores.

Básicamente la necesidad surgió ya que revisando un proyecto que está casi listo para su entrega final, nos percatamos que en uno de los infinitos procesos de re-creación de base de datos (que la bajaban y la volvían a crear), los datos de algunos conjuntos de combos de selección relacionados entre si (como puede ser país, región, estado, provincia, condado) no eran consistentes.

En este caso (sumamente particular), la relación (lo que podríamos decir "llave foránea") es un descriptor en texto, y el comité creativo por algún misterioso motivo puso en algunos combos datos en mayúsculas con acentos, en otros en minúsculas y todas las variaciones que se puedan imaginar.

El resultado de esto fue que el proceso de filtro que cargaba "el siguiente" combo relacionado, traía todos los datos, ignorando cualquier relación esperable.
Para evitar esto, y suponiendo posible inconsistencia en los datos, se debía construir un filtro personalizado que hiciera que cadenas de caracteres como "REPUBLICA     DE MÉXICO" y "República de México" fueran comparables, y que el resultado fuera true.

Para ello lo más sano era eliminar acentos y espacios, pasar todo a mayúsculas y comparar.

El código:


app.filter('cleancompare', function(){
    return function(items, filterObj){
        if (filterObj === false) {
          return items;
        }
        
        if ((filterObj || angular.isUndefined(filterObj)) && angular.isArray(items)) {
            var newItems = [];
            angular.forEach(items, function (item) {
                var matches = true;                             
                var kArr = Object.keys(filterObj);
                for(key in kArr){                    
                    var cleanItemAttr = removeDiacritics(item[kArr[key]]).replace(/[^\w]/gi, '').toUpperCase();
                    var cleanObjAttr  = removeDiacritics(filterObj[kArr[key]]).replace(/[^\w]/gi, '').toUpperCase();
                    matches = (cleanItemAttr != cleanObjAttr)?false:matches;  
                    // Descomentar la línea únicamente si es estrictamente necesario depurar,
                    // ya que el rendimiento se ve seriamente perjudicado para conjuntos muy 
                    // grandes de datos.
                    /*if(matches){ console.log('Comparacion realizada: ', cleanItemAttr, cleanObjAttr); }*/
                }
                if(matches){
                    newItems.push(item);
                }
            });
            
            items = newItems;
        }
        
        return items;
    }
});
 
La función removeDiacritics() la saqué de http://stackoverflow.com/questions/18123501/replacing-accented-characters-with-plain-ascii-ones
Disfruten ;) 

lunes, junio 30, 2014

Oracle Instaclient SQL Plus en Ubuntu

Probablemente algunos (como yo) requieren tener instalado SQL Plus de Oracle en sus equipos sin tener que instalar Oracle completo. Para que funcione correctamente hay que hacer algunas cosas, y aquí les explico cuales son para que se ahorren algunos dolores de cabeza.

Paso a paso

  1. Descargar el InstaClient: Oracle es "algo" quisiquilloso cuando se trata de sus herramientas, así que la opción es buscar en Google o navegar directamente en el sitio de esta empresa.
  2. Descomprimir InstaClient: Típicamente habrán descargado el archivo comprimido. Cuando se trata de herramientas que requieren instalación manual yo las dejo en la carpeta /opt

  3. Configurar variables de ambiente: Estas son varias, así que creé un script que las setea y des-setea según corresponda:
unset NO_PROXY
unset UBUNTU_MENUPROXY
unset no_proxy

unset ORACLE_HOME
export LD_LIBRARY_PATH=/opt/instantclient_12_1
para la versión 11_2 es análogo pero tendrán que poner la carpeta que corresponde.

Finalmente ejecutar SQL Plus: Fácil y bonito, desde la misma ruta
./sqlplus
 Y eso debiera funcionar.

Bonus: Si quieren ejecutar  una conexión para administrar una base de datos remota (y poder reiniciar la base con un shutdown abort, por ejemplo) el comando es:
./sqlplus 'usuario/clave'@IP_de_la_BD/SID as sysdba

obviamente cambiando los datos acorde.

lunes, junio 16, 2014

Emprendimiento busca desarrollador: Aquí hay un problema

Hace poco les contaba algunas apreciaciones personales respecto a los emprendimientos TI. Hoy les quiero comentar, queridos y honorables lectores, un par de problemas que he notado, cuando los mismos chicos que ayudaba con su emprendimiento comienzan su búsqueda de  desarrolladores.

Cito el aviso (y omito los enlaces para proteger a los "inocentes"):
Chicos estamos buscando a un desarrollador para que se convierta en nuestro CTO . Aquí mayor información ... [link]
Somos un NUEVO EMPRENDIMIENTO y estamos en busca de un DESARROLLADOR Back-end, idealmente con conocimientos de Front-end, nos encontramos en el desarrollo del M.V.P.

Lenguajes: PHP, Java, Ruby on Rails, CoffeeScript y bases de datos como MySql, Mongodb.

Si eres Entusiasta, Emprendedor y te gusta la Música, contactanos para concretar una reunión!

Buscamos alguien que llegue a ser nuestro socio, por ahora no hay dinero de por medio pero si un gran Proyecto.

Start Small - THINK BIG!
Lo primero que me llama la atención del aviso es el tipo de requerimientos que se solicita:
  • PHP
  • Java
  • Ruby on Rails
  • CoffeeScript
  • Bases de datos como MySql, MongoDB
Personalmente aún no me ha tocado ver un proyecto en el cual converjan PHP, Java y RoR, por lo que se me hace que fue producto de una búsqueda en Google de que lenguajes y tecnnologías son los más utilizados en los emprendimientos.
Con las bases de datos me sucede algo similar.

Lo no tan bueno de considerar en el aviso una variedad de tecnologías es que refleja poca claridad respecto de que se necesita en términos informáticos.

Lo segundo que me llama la atención es lo que se busca:
  • Un socio y CTO

CTO es el nombre de fantasía para "el informático" del equipo (Chief Technology Officer, que le dicen) y todas las siglas de CEO, CDO, etc. son las denominaciones de moda de las startups para los puestos "gerenciales". A proposito ¿no que estaban buscando desarrollador? ¿CTO desarrollador? ¿Existe eso?

Esto por si mismo no es tan terrible, salvo que se suma a lo tercero qeu me llama la atención:
por ahora no hay dinero de por medio pero si un gran Proyecto.
El problema aquí es que el CTO al ser "EL informatico del equipo", va a ser además quien se haga cargo de las definiciones técnicas, y de buena parte de la implementación, si es que no toda.

Mano en el corazón: ¿Trabajarían gratis?, considerando que por muy emprendimiento que sea igual hay que cumplir con los plazos que se hayan definido.

Y sigo viendo problemas, el "gran Proyecto" es una calificación absolutamente subjetiva para una idea que no se conoce a priori.
Decir inmediatamente que no hay dinero mata al instante el posible interés de buena parte de los potenciales candidatos. No le da tiempo al emprendimiento de venderles su excelente idea y proyecto, y convencerlos que realmente vale la pena tomar el riesgo de formar parte de este equipo.

¿Cómo mejoraría el aviso?

  1. Eliminar el exceso de honestidad. OK, sabemos que no hay dinero, pero no es estrictamente necesario mencionarlo, sobretodo si quieres darle la oportunidad a tu emprendimiento de convencer a los candidatos. Sin tener conocimientos formales en marketing, creo no equivocarme al pensar que el objetivo es vender la idea, convencer que es buena. Si no motivas a tus "clientes" (en este caso candidatos al puesto de desarrollador) dificilmente van a "comprar" tu idea.
  2. Eliminar la promesa de CTO. Se ve bonito, pero ¿qué buscan? ¿Desarrollador o CTO o ambas?... ¿han evaluado la compatibilidad real de ambos cargos?
    Aparte, y esta es opinión 100% personal, ser CTO de un emprendimiento que aún no se concreta es ponerse un título de papel higiénico, se deshace con agua. No es algo que pondría en mi LinkedIn.
  3. Ser claro en las especialidades requeridas para postular. Un profesional que maneje esta variedad de tecnologías no es un profesional barato, y posiblemente tampoco tenga demasiado tiempo disponible para dedicar a la filantropía, ergo no muy compatible con emprendimientos donde no haya un incentivo monetario.

jueves, junio 05, 2014

AngularJS UI Router, resolve & Unknown service provider ERROR

La noche de ayer me quedé en la oficina terminando de corregir algunos aspectos de una aplicación. Una aplicación móvil híbrida con AngularJS, Angular UI Router y Bootstrap. El código estaba bien, pero uno de mis controladores estaba gatillando el error Unknown service provider.

Angular UI Router  permite conceptualizar una aplicación web como una máquina de estados.
Cada acción que se realiza puede ser un estado separado, y cada estado, desde el enfoque de desarrollo que estamos adoptando, tiene sus propias vistas.
A su vez, cada vista esta manejada por su propio controlador, y eventualmente antes de cargarse puede requerir que resuelva determinada petición (resolve).

Ejemplificando con código:

app.config(function ($stateProvider, $urlRouterProvider) {
    $urlRouterProvider
          .when('/', '/login')
          .otherwise('/');


    $stateProvider
        .state('login', {
            url: '/login'
            , views: {
                'login': {
                    templateUrl: 'include/login.include.html'
                    , controller: 'loginCtrl'
                }
            }
            , onEnter: function() {
                loggedin = false;
                localStorage.setItem('loggeduser', null);
            }
        })
        .state('plan', {
            url: '/plan'
            , views: {
                'menu': {
                    templateUrl: 'include/menu.include.html'
                    , controller: 'menuCtrl'
                } 

                , 'plan': {
                    templateUrl: 'include/plan.include.html'
                    , controller: 'planCtrl'

                }
                , 'client': {
                    templateUrl: 'include/client.include.html'
                    , controller: 'clientCtrl'
                    , resolve: {
                        clients: ['pouchWrapper', function(pouchWrapper){
                            var cliMap = function(doc){
                                if(doc.dbtable === 'cli'){
                                    emit(doc, null);
                                }
                            }

                            // Rescata el listado de clientes desde un repositorio local
                            return pouchWrapper.retrieveList(cliMap);
                        }]
                    }                  
                }            }           
            , onEnter: function($location) {              
                if(!loggedin){
                    console.log('No ha ingresado al sistema');                                       
                    $location.path('/logout');
                }
            }
        }) ;

});

Si se dan cuenta algunas plantillas (template) tienen indicado cual es su correspondiente controlador (controller).

Y en el controlador clientCtrl

app.controller('clientCtrl', ['$scope', '$location', 'clients', 
    function($scope, $location, clients){
        // ... aqui va mucho código
    }]);

El problema es que estando bien codificada la máquina de estados, y cargando cada vista como correspondía, AngularJS reportaba el error Unknown service provider para clients, sin indeicar origen del error ni líneas de referencia (es una maravilla depurar código a ciegas :-/ ).
Después de mucho buscar y leer en la Wiki y sección de Issues del Github de Angular UI Router, llegué a un post en StackOverflow (lo siento, perdí el enlace  original), donde explicaban que
el error se genera cuando el estado tiene el controlador referenciado tanto en la configuración como dentro de la plantilla.


En la plantilla include/client.include.html

<div data-ng-controller="clientCtrl">
    <!-- ... aquí va el contenido de la plantilla para el bloque client -->
</div>


El error lo he destacado en negrita, el controlador o está referenciado en la configuración del estado, o está referenciado dentro de la plantilla, pero NO en ambos.

Después de ver la solución, y corregir el problema (eliminando la referencia al  controlador en la plantilla) es entendible lo que está sucediendo. Si recuerdan, el controlador recibe como tercer parámetro clients (que es lo indicamos en el atributo resolve del estado, que queremos resolver antes de desplegar) . Al poner la referencia directamente en la plantilla, clients queda vacío, ergo Unknown service provider.




miércoles, mayo 28, 2014

Yo vs emprendimientos TI

Inicialmente iba a ser un artículo lleno de argumentos y explicaciones. Era sobre mi propio enfoque y el porqué de mi incompatibilidad con los emprendimientos. Al final el éxito de un emprendimiento se resume en una sola cosa: 
SACRIFICIO.

Hace algún tiempo tuve la oportunidad de conversar en extenso con un suizo, residente en Chile. La conversación con este exitoso empresario del rubro inmobiliario pronto derivó en su visión sobre los emprendimientos en Chile.
Me comentó sobre una experiencia que tuvo con unos amigos de él. Tenían una idea muy buena, auspiciosa en cuanto al mercado y a las potenciales ganancias a obtener. Él con su experiencia les señaló:
"La idea es buena, tiene potencial, pero para poder llevarla a cabo tienen que destinar al menos 10 horas diarias para trabajar en ella."
Se podrán imaginar que la réplica fue que no podían destinar 10 horas diarias de trabajo, ya que todos los involucrados podían entregar dedicación parcial al proyecto, debido a que trabajaban jornada completa.

Me arriesgo a decir que un alto porcentaje de los emprendimientos que quedan en nada (léase sólo en la idea y las buenas intenciones) se debe a que los integrantes no pueden destinar el tiempo necesario para trabajar en el proyecto.
Lamentablemente los emprendimientos no pueden llevarse a cabo a ritmo propio o cuando tengas ganas/puedas de dedicar tiempo a ello.

Finalmente todo se reduce a SACRIFICIO. ¿Cuánto estás dispuesto a sacrificar?:
  • ¿Sacrificarías no ver a las personas que amas? 
  • ¿Sacrificarías horas de sueño y descanso? 
  • ¿Sacrificarías dejar de ganar una remuneración por hacer lo mismo (o similar)? Nota: Puse dejar de ganar y no perder, hay una sutil diferencia.
  • ¿Sacrificarías rendir en tu trabajo actual por dedicar tiempo a tu emprendimiento? y de paso asumir el costo que esto puede significar (normalmente ser despedido).
Y quedo corto en este listado. Responder NO a cualquiera de estas preguntas ya es un riesgo que no estás dispuesto a tomar.

¿Cuánto estás dispuesto a sacrificar?
¿Cuánto?


En mi caso las cuentas eran negativas, demasiadas responsabilidades en mi quehacer cotidiano, repercusiones familiares, costo de oportunidad descompensado y una que por donde la mirara tenía demasiado peso. Después de una jornada de 8 horas diarias frente a un computador, resolviendo problemas de las más variadas especies, física y mentalmente termino disminuido para seguir haciendo lo mismo en casa (fuera de horario).

Hay que ser sincero con uno mismo y no tratar de auto-convencerse con falsas ilusiones. Las charlas TED y de la universidad suenan muy lindas y convincentes, pero llevarlas a la práctica dependerá de realidad personal de cada uno.


Spring REST Services y el error Required String parameter is not present

Desarrollando una API REST utilizando Spring MVC, y consumiéndola con AngularJS, me enfrenté al problema "Required String parameter is not present". Así es como lo solucioné.

Hace poco "vendí" (en rigor sólo convencía  mi jefe que es buena idea tomar este enfoque) una idea para abordar nuevos desarrollos. Consiste en desarrollar una API REST, utilizando el generador de código Telosys, y generar las interfaces con HTML5, CSS3 y JavaScript de modo de consumir los servicios con AngularJS.
Nada nuevo dirán, pero ofrece la ventaja que el mismo desarrollo web puede ser portado sin demasiado esfuerzo a una aplicación móvil usando Phonegap, o bien a una aplicación de escritorio utilizando Node-Webkit.

Este tipo de desarrollo resulta bastante rápido, y si logras una combinación entre Angular-UI-router y plantillas web con controladores propios (los controllers de AngularJS), se obtiene una modularidad bastante atractiva.

El problema

El código no tenía problemas, pero al tratar de realizar una llamada POST con Restangular a pesar de que el JSON con los datos que debía recibir la petición estaba bien construido, la llamada arrojaba el error:
Required String parameter 'usr' is not present

Soluciones propuestas

De las soluciones propuestas, después de realizar muchas búsquedas, ninguna funcionó:
  • Forzar que todas las peticiones POST indicaran en sus headers
    Content-Type = 'application/x-www-form-urlencoded' con el código:
  • $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';   
  • Agregar el atributo enctype="application/x-www-form-urlencoded" a la etiqueta form.
  • Realizar la llamada con AngularJS nativo vs usar Restangular.

Hasta pensé en cambiar el enfoque y usar HATEOAS, pero significaba realizar demasiados cambios a la aplicación (en rigor regenerar el código, Telosys se encarga del trabajo sucio).

Solución

Dí con este artículo de StackOverflow, donde explican que el servicio debe recibir un objeto que tenga todos los parámetros de la petición. Algo como:
@RequestMapping(value = "events/add", method = RequestMethod.POST)
public void addEvent(@RequestBody CommandBean commandBean){
    //some code
}

donde se debe indicar que el objeto (puede ser un POJO) CommandBean es el  @RequestBody. Y Spring se encargará de capturar los parámetros adecuadamente.
Y eso funcionó sin problemas.

miércoles, marzo 26, 2014

GulpJS amistoso con AngularJS

Hace poco después de mi lectura diaria descubrí GulpJS. Es una simpática herramienta de línea de comando que permite optimizar muchas cosas del desarrollo web, desde la minimización de imágenes, hasta la "liposucción de código" como le llamamos en la oficina al proceso de eliminar comentarios y mensajes de debug.
El resultado normalmente es un archivo .js minimizado, un archivo .css también minimizado, e imágenes y archivos .html "optimizados".

No les voy a enseñar a usarlo, eso lo pueden ver en detalle en los siguientes enlaces (todos en inglés):
Los primeros problemas a los que me enfrenté fueron básicamente que las configuraciones por defecto son muy agresivas, por lo que mis HTMLs quedaron sin algunos atributos necesarios para que mis controladores Angular funcionaran, y que derechamente mis controladores Angular dejaron de funcionar.

Después de leer algo de documentación para revisar las opciones de los plugins de Gulp que decidí usar, y trás algunas pruebas, llegué al siguiente código, que me ha arrojado los mejores resultados:

// Include gulp
var gulp = require('gulp'); 

// Include Our Plugins
var jshint = require('gulp-jshint');
var concat = require('gulp-concat');
var changed = require('gulp-changed');
var uglify = require('gulp-uglify');
var rename = require('gulp-rename');
var stripDebug = require('gulp-strip-debug');

// Lint Task
gulp.task('lint', function() {
    return gulp.src('js/*.js')
        .pipe(jshint())
        .pipe(jshint.reporter('default'));
});

// Concatenate & Minify JS
gulp.task('scripts', function() {
    return gulp.src(['js/angular.min.js', 'js/Directive/bindonce.min.js', 'js/jquery-2.0.3.min.js', 'js/bootstrap.min.js',  'js/app.js', 'js/*.js', 'js/Service/*.js', 'js/Filter/*.js', 'js/Directive/*.js', 'js/Controller/*.js'])
        .pipe(concat('appjs.js'))
        .pipe(stripDebug())
        .pipe(gulp.dest('dist'))
        .pipe(rename('app.min.js'))
        .pipe(uglify({ mangle: false }))
        .pipe(gulp.dest('dist'));
});

// include plug-ins
var minifyHTML = require('gulp-minify-html');
 
// minify new or changed HTML pages
gulp.task('htmlpage', function() {
  var htmlSrc = '*.html',
      htmlDst = 'dist';
 
  gulp.src(htmlSrc)
    .pipe(changed(htmlDst))
    .pipe(minifyHTML({ empty: true, spare:true, quotes: true }))
    .pipe(gulp.dest(htmlDst));
});

// include plug-ins
var autoprefix = require('gulp-autoprefixer');
var minifyCSS = require('gulp-minify-css');
 
// CSS concat, auto-prefix and minify
gulp.task('styles', function() {
  gulp.src(['css/bootstrap.min.css', 'css/*.css'])
    .pipe(concat('styles.min.css'))
    .pipe(autoprefix('last 2 versions'))
    .pipe(minifyCSS())
    .pipe(gulp.dest('dist'));
});

// default gulp task
gulp.task('default', ['htmlpage', 'scripts', 'styles'], function() {
});

Lo único que no pude resolver a través de parámetros (y si alguien lo sabe se agradece si comparten el dato) fue el hecho que el plugin minify-html se "come" mis espacios en blanco intencionales (a veces necesarios) y los atributos que no tienen valor (como el bindonce). Tan grave no es si sabes donde ponerlos de vuelta, pero eso ya es parte del trabajo manual.