TDD in Clojure

16 febrero, 2016 Los comentarios están cerrados

(This is an article I published a few weeks ago in Funding Circle’s engineering blog, here)

It’s been a few months since I first approached Clojure, and approaching a functional language for the first time is quite an experience that makes you revisit and reevaluate many of your past experience and know-how with object-oriented (OO) languages.

Testing and TDD/BDD is one of the main foundations of high quality software. But TDD/BDD doesn’t feel as natural in functional languages as it does in OO languages; this has been one of my main issues working with Clojure.

Do I really need to test as much as before? How do I test code composed of functions only? How do I mock? Should I mock? Are functional languages hard to test or am I doing something wrong?

This post is aimed at giving some advice to how to TDD in Clojure, given that many OO techniques both for testing and testability, are not directly applicable to Clojure. This is a summary of the little information I found about adapting TDD to programming in Clojure, together with my own experience. Looking back, I can summarize three main concerns:

  • Differences in TDD flow
  • What testable code means in Clojure
  • How to implement common testing techniques (i.e. mocking)

Warning: These advices come from just few months of experience in Clojure, so they might be incomplete, or just plainly wrong!

Differences in TDD flow

The main difference I’ve found is moving from the classical top-down design, to a bottom-up strategy.

A bottom-up approach feels more natural, helps keeping your impure functions under control, and removes a lot of overhead by avoiding mocking in many situations.

Uncle Bob Martin recommends this approach in the article TDD in Clojure but mainly because of a lack of mocking tools in Clojure by the time he wrote it (2010). That’s no longer the case, but I would still recommend giving a try to a bottom-up approach. For example, try to build your DB layer first, then start going up till you reach the UI. This makes easier to keep all I/O isolated in a single namespace.

In any case, I recommend ignoring the quite spread opinion that functional languages do not need unit testing or only a small amount. I think this belief is based on a misunderstanding of certain properties of some functional languages.

Some functional languages do need much less testing, and people mistakenly confer this to its functional nature. In the case I’m familiar with, Haskell, the reduced amount of testing is due to the combination of its functional paradigm, its side-effect encapsulation (monads), and its static type system with type inference. It’s not that it doesn’t need tests; it’s that it has a built-in testing system called type system. And it only helps with some low-level testing: you still need your usual amount of business logic tests.

But Clojure is a dynamic language. The compiler does not reason about whether a certain function can receive an invalid type, using type inference. Not only that, but Clojure does not help with keeping side effects under control. Because of this, I recommend to keep your test coverage as high as you do with any other OO language. Even if a reduced-test approach is feasible, I don’t think it’s a good approach for a Clojure newbie.

Testability in Clojure

I would say that most of the problems I’ve had with TDD, happened because of low testability of my code.

What does testability mean in Clojure? Most people agree on pure functions being the main testability enhancer in a functional language. Also, dependency injection helps both testability and function pureness. Avoiding untestable code in namespaces and changing your OO design mindset is also important.

Pure functions

A pure function can be defined as a stateless function, or a referencially transparent function, or plainly as a function that has no side effects and, for a given input, always returns the same output. Usually, this mean no state, no I/O, no side effects.

For example, random() is not a pure function, because it is not deterministic, you may get different output when calling it with the same input. A function that writes to a database is not pure, because it has a side effect. A function that calls three impure functions and “branches” the execution is not pure, because it has side effects (well, it depends). A function that makes a decision by reading from the database, is not pure either because it can return different results for the same inputs depending on the content of the database.

So, you should always try to have a clear boundary between pure and impure functions in your code. Usually, you’ll want to keep your impure functions free of business logic and locked up in the lower (DB) and the upper (UI) layers, keeping the rest of the code as a chain of pure functions. Just as a comment, I haven’t managed to do that yet, but the closer to that approach I am, the easier it is to test my code.

Dependency injection

Dependency injection can help in two different ways. The more obvious is, it makes mocking easier: just pass the mock as an injected dependency, and you are good to go. The second way is, it allows you to turn an impure function into a pure one.

Dependency injection in Clojure has its own difficulties in contrast with OO languages. Where in OO languages you typically inject an object or a class as a dependency and store it in your state, in functional languages you only deal with functions being injected into other functions, usually without a state for storing the injected dependencies.

This adds quite an overhead. Given that you have no internal state like an object does, you cannot store your injected dependency in that state. So, you need some other technique to pass the injected function to the receiver function.

Five faces of dependency injection contains a compendium of five different techniques to deal with this. I would recommend either using function arguments, or try a reader monad.

In any case, injection adds an overhead. So, we should try using it only when facing a hard to mock function, or for increasing pureness.

Or try to replace dependency injection with function composition. For example:

(defn should-i-print-this?
  [arg]
  (= arg :yes))

(defn print-it
  [arg decider]
  (when (decider arg)
    (prn arg)))

(print-it :yes should-i-print-this)

but with function composition:

(defn filter-to-print
  [arg]
  (when (= arg :yes)
    arg))

(defn print-it
  [arg]
  (when arg
    (prn arg)))

(def print (comp print-it filter-to-print))

(print :yes)

Deciding whether the composition or the injection version is better depends on the situation. It’s just another tool that might be useful!

Increasing pureness with dependency injection

Dependency injection can help to keep impureness under control, by extracting impure behavior to functions with as little business logic as possible, and then injecting them where needed. This way, we can keep an otherwise impure function pure:

(defn transform-if-exists
  "This function is pure."
  [entity checker]
  (when (checker (:id entity))
    (transform entity)))

(transform-if-exists entity db/checker)

instead of

(defn transform-if-exists
  "This function is not pure"
  [entity]
  (when (db/checker (:id entity))
    (transform entity)))

(transform-if-exists entity)

The first function is pure. You can test it without worrying about fixtures, factories or similar. The second one is not, it needs you to redefine db/checker or use some db fixtures. It’s harder to test. It’s slower to test.

Assembly line vs Object interactions

As OO developers we are used to have code whose execution path branches instead of keeping a single line of execution. We make our objects to speak to a lot of other objects and our programs end up being a composition of objects interacting with each other.

For example, if we need to save a record, then turn some flag on it, and then transform it, we tend to do this:

(defn- save
  [thing]
  (db/save thing))

(defn- mark
  [thing]
  (db/update (assoc thing :mark true)))

(defn- transform
  [thing]
  (assoc thing :name "I'm transformed"))

(defn save-mark-and-transform
  [awesome-thing]
  (db/save awesome-thing)
  (db/mark awesome-thing)
  (transform awesome-thing))

The problem is, this approach is not suited for functional languages because of the amount of side effects.

Instead, we should try to think about our programs as assembly lines, where there is one single flow of execution, and the output of one element is the input of the next one. The previous code example would look like this:

(defn- save
  [thing]
  (db/save thing)
  thing)

(defn- mark
  [thing]
  (let [marked-thing (assoc thing :mark true)]
    (db/update marked-thing)
    marked-thing))

(defn- transform
  [thing]
  (assoc thing :name "I'm transformed"))

(defn save-mark-and-transform
  [awesome-thing]
  (-> awesome-thing
      save
      mark
      transform))

The difference is not only syntactic, but structural. Each function takes previous function’s output as its input. This means, we are enforcing each function to return something, instead of triggering a side effect, and we are keeping a single flow of execution. Also, this mean we can just use composition for building new functions:

(defn- save
  [thing]
  (db/save thing)
  thing)

(defn- mark
  [thing]
  (let [marked-thing (assoc thing :mark true)]
    (db/update marked-thing)
    marked-thing))

(defn- transform
  [thing]
  (assoc thing :name "I'm transformed"))

(def save-mark-and-transform (comp save mark transform))

The more I code this way in Clojure, the easier to maintain my code is (at least for now: ask me in six months, maybe I’m wrong!).

Untestable code in namespaces

Avoid complex code to execute at namespace load time. Nothing more than that.

Testing techniques

I really recommend reading chapter four of Test-Driven Development in Clojure (Niclas Nilsson, 2015). It’s a good compendium of basic testing techniques for Clojure.

Mocking

With dependency injection

If your function accepts its dependencies as arguments:

(defn awesome-function
  "I'm so awesome I have my dependencies injected"
  [some-function stuff1 stuff2]
  (let [stuff {:a-key stuff1
               :another-key stuff2}])
    (some-function stuff))

testing it can be as simple as:

(deftest awesome-function
  (let [mock-function (constantly "whatever")]
    (is (= "whatever" (awesome-function mock-function 3 5)))))

Without dependency injection

If your function does not allow to inject a certain dependency, you can still test it. Assuming we have:

(defn crappy-function
  "I'm so crappy I have my dependencies hardcoded"
  [stuff1 stuff2]
  (let [stuff {:a-key stuff1
               :another-key stuff2}])
    (some-namespace/some-function stuff))

testing it would be:

(deftest crappy-function
  (with-redefs [some-namespace/some-function (constantly "I am really crappy")]
    (is (= "I am really crappy" (crappy-function mock-function 3 5)))))

If we use Midje, a test framework for Clojure, it looks slightly better:

(facts "about `crappy-function`"
  (fact "returns whatever some-namespace/some-function returns"
    (crappy-function 3 5) => "I am really crappy"
    (provided (some-namespace/some-function anything) => "I am really crappy")))

But in any case, it's better to inject the dependency when possible. Using redefinitions is not always feasible —for example, with Clojure protocols— and using dependency injection tends to produce more pure functions, which are easier to test.

Spies

What if you want to check whether a function has been called, and with which
parameters?

Well, in that case you should first realise you are testing a side effect, and decide whether you really need it or you can somehow avoid it.

Using the previous example, and using midje:

(facts "about `crappy-function`"
  (fact "returns whatever some-namespace/some-function returns"
    (crappy-function 3 5) => "I am really crappy"
    (provided (some-namespace/some-function {:a-key 3 :another-key 5}) => "I am really crappy" :times 1)))

Note the different provided statement, together with the number of calls we expect.

You can also spy using clojure.test, using atoms to store the calls to a mock function:

(deftest crappy-function
  (let [calls (atom [])]
    (with-redefs [some-namespace/some-function (fn [arg] (swap! calls conj arg) "I am really crappy")]
      (is (= "I am really crappy" (crappy-function mock-function 3 5)))
      (is (= @calls [{:a-key 3 :another-key 5}])))))

So, this is more or less my compendium of lessons learned during my first six months with Clojure. Many things are probably wrong, or I will change my mind in a few more months. But in the meantime, I hope these ideas are useful to someone else!

From Levelap to Stack Builders

Next week is my last week as a member of the Levelap team. After a year and a half being part of this project the time has come for a change, for facing new challenges, an learning new technologies and workflows.

During this year and a half I’ve felt supported and appreciated, and I’ve been listened to as in no other place I’ve worked in during my life. Although the first months were tough, and it took a great effort to change the previous enterprise culture, I think we’ve made a great progress in a little time, and in the right direction. I can only thank to people like Pablo Pazmiño and Rafael Meneses the really good moments we’ve been through, how much I’ve learned along the way, and all the trust they’ve put in me. I’ll miss you, panas.

And where am I heading to? Well, in a week I start working in Stack Builders!. Stack Builders is a small software development company from New York city with offices in Quito, focused in the quality of its code. Until now they’ve been working with Ruby, but are now involved in the process of becoming a Haskell company. The idea of learning how to do real work using the functional paradigm is one of my main reasons for joining their team. Also, I’ll be working with people from whom I will learn a lot, and with whom I will have a good time.

Here we go!

Categorías:English, Personal Etiquetas: ,

De Levelap a Stack Builders

La semana que viene es mi última semana como parte del equipo de Levelap. Tras más de año y medio formando parte de dicho proyecto, ha llegado el momento de cambiar de aires, de enfrentarme a nuevos retos, y de aprender nuevas tecnologías y formas de trabajo.

Durante este año y medio me he sentido arropado, valorado y escuchado como en ningún otro lugar en el que he trabajado durante mi vida. Aunque los primeros meses fueron duros y costó cambiar la cultura de empresa existente, creo que hemos avanzado mucho en poco tiempo, y en la dirección correcta. No puedo más que agradecer a personas como Pablo Pazmiño y Rafael Meneses los buenos momentos que hemos pasado, lo mucho que he aprendido en el proceso, y la confianza que siempre han depositado en mí. Os echaré de menos, panas.

¿Y a dónde me dirijo? ¡Pues en una semana empiezo a trabajar en Stack Builders!. Stack Builders es una pequeña compañía de desarrollo de software de Nueva York con oficinas en Quito, enfocada en la calidad de su código. Hasta ahora han venido trabajando con Ruby, pero están en pleno proceso de cambio hacia Haskell. La idea de aprender a programar bajo el paradigma funcional es una de las principales razones para unirme a su equipo. Además, voy a trabajar con personas de las que podré aprender mucho, y con las que seguro que pasaré muy buenos momentos.

¡Allá vamos!

Categorías:Español, Personal Etiquetas: ,

Hackwell in Haskell: a Haskell hackathon in StackBuilders

Presenting a solution for the snail kata.

Presenting a solution for the snail kata.

Today have taken place in the StackBuilders offices in Quito what seems to be the first Hackathon using a funcional language, in Ecuador. For this ocasion, we’ve been using Haskell.

Haskell is a functional programming language created in 1990 that takes its name from Haskell Curry, an american mathematician in which works about logics are partially based the current functional programming languages. Haskell is a strongly typed language, although it differs from other functional languages as Clojure in not forcing the data structures inmutability.

During the day, the problem proposed was solving the snail kata in Haskell. The snail kata consist in, given a squared matrix, return an array with all the matrix elements sorted as is shown in the following diagram:

 

We sort the matrix elements following an helix

We sort the matrix elements following an helix

 

So, for the next matrix:

array = [[1,2,3],
[4,5,6],
[7,8,9]]

the expected result of applying snail should be:

snail(array) #=> [1,2,3,6,9,8,7,4,5]

 

Speaking about the hackathon itself, I must say that it was really fun, that I’ve learned a lot, and that I’m very satisfied with the solution that my pair and me have developed, taking into account that it has been our first code in Haskell. There have been beer, pizza, and several funny moments🙂

About our solution, we’ve developed a first algorithm that:

  • Extracts the upper row.
  • Extracts the right column without the first element (which is already included in the upper row).
  • Concats the above with the result of calling again the function with the lower left submatrix, rotated 180 degrees.

After that, we have refined it to the following algorithm:

  • Extract all the matrix perimeter, concatenated in the correct order.
  • Concat the above with the result of calling again the function with the inner matrix (without the perimeter).

The solution is available in my Github account.

As pending tasks, I still need to learn how to test in Haskell. It has been quite an experience to program without tests after so much time applying TDD 100% of my time, and it has been like driving a car without safety belt. Also, I’ve confirmed again how much time is wasted when you lack automated tests.

 

Categorías:English Etiquetas: , ,

Hackwell in Haskell: hackathon sobre Haskell en StackBuilders

Presentando una solución a la kata snail.

Presentando una solución a la kata snail.

Hoy se ha celebrado en las oficinas de StackBuilders en Quito el que parece ser el primer Hackathon en un lenguaje funcional del Ecuador. Para la ocasión, hemos utilizado Haskell.

Haskell es un lenguaje de programación funcional aparecido en 1990, que toma su nombre de Haskell Curry, matemático estadounidense en cuyos trabajos en lógica se basan parcialmente los actuales lenguajes funcionales. Haskell es un lenguaje fuertemente tipado, que sin embargo difiere de otros lenguajes funcionales como Clojure en no forzar la inmutabilidad de las estructuras de datos.

Durante el día de hoy, se nos propuso resolver en Haskell la kata snail. La kata snail consiste en, dada una matriz cuadrada, obtener un array con sus elementos ordenados recorriendo la matriz según se indica en el diagrama:

 

Recorremos la matriz siguiendo una espiral

Recorremos la matriz siguiendo una espiral

 

Es decir, para la siguiente matriz:

array = [[1,2,3],
[4,5,6],
[7,8,9]]

el resultado de snail sobre la misma debería ser:

snail(array) #=> [1,2,3,6,9,8,7,4,5]

 

Sobre el desarrollo del Hackathon, hay que decir que ha sido muy divertido, que he aprendido muchísimo, y que estoy muy satisfecho con la solución que mi pair y yo hemos desarrollado, teniendo en cuenta que era nuestro primer código en Haskell. Ha habido cervezas, pizza y momentos divertidos🙂

Sobre la solución, hemos desarrollado un primer algoritmo que:

  • Extrae la fila superior.
  • Extrae la columna derecha sin el primer elemento (que ya está incluido en la fila superior).
  • Concatena lo anterior con el resultado de volver a llamar a la función con la submatriz inferior izquierda rotada 180 grados.

Posteriormente, hemos refinado el algoritmo a:

  • Extraemos todo el perímetro de la matriz, concatenado en el orden correcto.
  • Concatenamos lo anterior con el resultado de volver a llamar a la función con la submatriz interna (sin el perímetro).

La solución está disponible en mi cuenta en Github.

Como tareas pendientes, queda aprender cómo testear en Haskell. Ha sido toda una experiencia programar sin tests tras tanto tiempo aplicando TDD al 100%, y ha sido como conducir sin cinturón de seguridad. Además, he vuelto a confirmar el tremendo tiempo que se pierde cuando no se cuenta con tests automatizados.

 

Categorías:Español Etiquetas: , ,

Agilismo ‘waterfallero’

Y andaba yo “feliz-guiño-guiño” con mis gráficas, mis veintemil indicadores, mis plazos, mis documentos de análisis y diseño, mi margen de contribución esperado, etc… Total, que en eso que en la empresa deciden que el agilismo está de moda, y que hay que poder ponerse la medalla de agilistas. Nos mandan a los que andábamos con temas de gestión a un curso de scrum. Hasta aquí bien.

Llegamos al curso, que a la sazón era impartido por una empresa que vendía certificaciones en scrum. Y empiezan a hablarnos de sprints, de sprint reviews, de stand-ups, de sprint plannings y esas cosas. Y empiezan a aparecer un concepto: ‘my-scrum‘:

—”Ojo, si no se hace un stand-up diario, no estáis haciendo scrum: estáis haciendo my-scrum
—”Ni se os ocurra alterar un sprint durante el mismo: si lo hacéis no estáis haciendo scrum, sino my-scrum
—”El producto se muestra al cliente al final del sprint y no a medias: si no, estaríais haciendo my-scrum

Y en esto que alguien pregunta:

— “¿Qué pasa si hacemos my-scrum?”

Y ojo a la respuesta:

— “Que entonces la metodología no funciona

Estamos hablando de hace unos cuatro años. Tras escuchar esto, con mi mente waterfall queda claro que todo es más o menos lo mismo: una metodología más, pero de moda.

Ahora saltamos a unos meses después. La empresa, con una estructura jerárquica clásica intenta hacer sus pinitos con scrum, en un entorno de analistas, jefes de proyecto y plazos prefijados. Evidentemente, el asunto no funciona. En uno de los proyectos que gestiono, logro que me permitan probar scrum durante un minidesarrollo. Por supuesto con plazos fijos. Y por supuesto, cuando intento aplicar scrum, no acaba de ajustar con la realidad del proyecto. Pero persevero: de algún modo mágico, si logro evitar hacer my-scrum, la metodología funcionará. Por supuesto, al final el intento de scrum queda en algo vacío y casi ridículo.

Ahora, viéndolo con unos años de perspectiva, me doy cuenta de que una parte importante de la industria no ha entendido el agilismo. Creen que son unas metodologías más, que se pueden aplicar igual que antes se aplicaba waterwall. Coges tu empresa clásica, pagas unas certificaciones para tus gestores, ¡y viva el agilismo! Y de paso, surgen a tu alrededor empresas que certifican.

El agilismo no es una metodología. El agilismo es un estilo de resolver problemas basado en unos principios. Es despejar todo lo accesorio para quedarte con la esencia: usar la razón, no los dogmas. Veamos el manifiesto ágil:

Valoramos más a las personas y las interacciones entre ellas que a los procesos y herramientas

Es decir: si crees que aplicando tal o cuál metodología vas a poder conseguir que unos programadores desmotivados, o poco dotados, o sin buen ambiente de equipo elaboren un producto de calidad, vas listo. Para obtener velocidad y calidad, necesitas buenos programadores. Olvídate de métodos mágicos. Los procesos y las herramientas están para que los buenos programadores se organicen bien, automaticen sus tareas repetitivas, y sean felices. No para camuflar malos profesionales, o condiciones de trabajo inadecuadas.

Valoramos más el software en funcionamiento que la documentación extensa

No te engañes: estás haciendo software. Cualquier cosa que te retrase o te descentre de la tarea de hacer software, es muy posiblemente desperdicio. Mantén algo de documentación pero solo en tanto te ayude a mantener/producir tu software de forma más eficiente. Además, yo añadiría que cuando más limpio es el código y mejor es tu UX, menos documentación necesitas: fuérzate a generar poca documentación como forma de estimularte a hacer mejor código y UX.

Valoramos más la colaboración con el cliente que el ceñirse a contratos rígidos

Nadie, salvo las lógicas excepciones fruto de la probabilidad, ha logrado realizar una recogida de requisitos a principios de un proyecto que explique de verdad qué quiere el cliente. No lo intentes, no se puede hacer. No gastes energías en evitar el cambio. En lugar de eso, vuelca tus esfuerzos en abrazar el cambio de un modo que te suponga el menor impacto posible. La conclusión habitual de esto es mostrar al cliente tus avances con mucha frecuencia. Pero no te quedes en eso: haz buen software, aplica TDD, patrones de diseño, etc. Todo esto ayuda a que un cambio sustancial en tu aplicación sea menos traumático.

Valoramos más adaptarte a los cambios que intentar seguir un plan fijo

Un poco mezclado con el anterior. El desarrollo de software es incertidumbre. Desde qué quiere el cliente, hasta cuánto tardarás en tener la idea feliz que te haga resolver tal bug. No se puede seguir un plan, salvo muy a grandes rasgos. Usa sprints, o no los uses, pero intenta que tu forma de trabajo implique redefinir de forma continua hacia dónde vas.

Pues bien, mi gran descubrimiento personal durante mis últimos años de trabajo es que no necesitas nada más que estos principios. Olvídate de metodologías, prácticas y demás: úsalas si te ayudan a seguir los principios ágiles. Pero no te ates: modifícalas si te conviene. Abandónalas en mitad de un proyecto si de pronto ya no aplican, y vuelve a asumirlas si vuelven a tener relevancia. Prueba y experimenta. Usa scrum y desfigúralo hasta que te diga “padre, mátame”.

Y sobre todo, mantente atento a los waterfalleros del agilismo. A aquellos que te dicen que my-scrum no funciona. A aquellos que te obligan a hacer un stand-up diario tenga o no tenga sentido.

Guárdate de la liturgia ágil.

Categorías:Español Etiquetas:

‘Waterfaller’ agilism

And there I was, “happy” with my charts, my twenty-thousand indicators, my deadlines, my analysis and design documents, my expected contribution margin, etc… So all of a sudden, the company decides that agile is starting to become quite trendy and we need to put on the agilist medal. The send me and everyone involved in project management to a scrum seminar. Not bad for now.

So there we were in this seminar, that at that time was teached by a scrum certification company. And they start talking about sprints, sprint reviews, stand-ups, sprint plannings and all that stuff. And a concept starts to emerge: ‘my-scrum’:

—”Be careful, if you don’t have a daily stand-up, that’s not scrum: that’s my-scrum
—”Don’t you dare to modify you current sprint: if you do that’s not scrum, but my-scrum
—”The sprint deliverable should be show to the client only at the end of the sprint: if not, that’s my-scrum

Being at this, someone asks:

— “What happens if we do my-scrum?”

And watch the answer:

— “Then the methodology does not work

We are talking about something that happened about four years ago. After hearing this, with my waterfall mind, it’s clear that this is more of the same: another methodology, but quite trendy.

Now we jump till a few months later. The company, with a classic hierarchical structure tries to take its first steps with scrum, in an environment full of analists, project managers and deadlines. Obviously, it doesn’t work. In one of the projects I’m in charge of, I manage to obtain permission to try scrum in a very small development. Of course with deadlines. And of course, when I try to apply scrum, it does not fit the project reality. But I persevere: in some strange an magical way, if I get to avoid degenerating to my-scrum, the methodology will work. Of course, at the end this scrum test ends being useless and almost ridicule.

Now, with a few years of perspective, I’m aware that quite a big part of this industry has not understand agilism. They think this is just a bunch of methodologies in the classic sense, that you can apply in the same way you applied waterfall methodologies. Take your company, pay for a few certifications for your managers, and long live the agilism! And in the way some certification companies have arised.

Agilism is not a methodology. Agilism is a style for solving problems, based in certain principles. Is to clear up all that is accesory, so you can focus on the essence: use reason, not dogmas. Let see the agile manifesto:

We value people and interactions between them, over processes and tools

So to say: if you think that applying a certain methodology you’ll be able to make a bunch of desmotivated, with a bad team culture, not very bright developers, do a high quality product, you’ve got another thing coming. To obtain speed and quality, you need good, happy developers. Period. Forget about magical methods. Processes and tools are for helping good developers to keep their work well organized, all their repetitive task automated, and to be happy. Not for hiding bad professionals, or bad working conditions.

We value working software, over comprehensive documentation

Don’t kid yourself: you are making software. Anything that delays or distracts you from making software, is quite possible a waste of time. Keep some documentation, but only as long as it helps you maintain/develop your software in an efficient way. Also, I would add that the more clean your code is and the better is your UX, the lesser your need for documentation is: try to force you to genere very little documentation as a way to encourage yourself to write better code and design a better UX.

We value customer collaboration, over rigid contract negotiation

Nobody, except for the logical exceptions result of probability, has achieved a requirement analysis at the start of a project that really describes what the customer wants and needs. Don’t try, it can’t be done. Don’t waste energies trying to avoid change. Instead of that, employ your efforts embracing the change in a way that its impact is the smaller possible. The usual conclusion of this is to show to your customer your progress as frequently as possible. But don’t stays with that: write good software, apply TDD, design patterns, etc. All this help to make a sustancial change in your application less traumatic.

We value responding to change, over following a fixed plan

A bit mixed with the previous one. Software development implies uncertainty. From what the customer really wants, till how long will it take you to have the flash of genius to resolve a given bug. You cannot follow a fixed plan, except in general terms. Work in sprints, or don’t, but try that your work flow implied a constant redefinition of where are you going.

So okey, my great personal discovery during my last years, professionally speaking, is that you don’t need anything else but this principles. Forget about methodologies, practices and so on: use them if they help you follow the agile principles. But don’t tie yourself: modify them if you need to. Abandon them at the middle of a project if they don’t fit your needs anymore, and go back to them if they fit your needs again. Try, experiment. Use scrum and disfigure it till it says to you “father, kill me”.

And above all, be aware of the waterfallers of agilism. Of those who tell you that my-scrum will not work. Of those who force you to do a daily stand-up no matter if it makes sense in your project.

Avoid the agile liturgy.

Categorías:English Etiquetas: