Páginas

lunes, 7 de octubre de 2019

Ejemplo de Verify FindOne() de MongoCollection de Jongo con JUnit y Mockito

Planteamiento y código

Este ejemplo está elaborado con Java 1.5, JUnit 4.12, Mockito 1.9.5, MongoDB driver 3.10.2, Jongo 1.3.0 y la base de datos MongoDB server 4.0.

Se muestra cómo preparar una prueba para un módulo de acceso a base de datos. Lo más remarcable es la forma de acceder a verificar que el método FindOne(query) es invocado una vez.
El siguiente módulo accede a una base de datos MongoDB, para buscar un usuario y comprobar si su contraseña coincide con una dada que contiene el objetoUsuarioBean. 

El módulo que accede a la base de datos y es el objeto de la prueba. O sea el SUT (Subject Under Test)

UsuarioColeccion.java

import org.jongo.Jongo;
import org.jongo.MongoCollection;
import com.mongodb.DB;
import com.mongodb.MongoClient;

public class UsuarioColeccion {
    private DB db;
    private MongoCollection mongoCollection;
   
    public MongoCollection getMongoCollection() {
      return mongoCollection;
    }
   
    public void setMongoCollection(MongoCollection mongoCollection){
        this.mongoCollection = mongoCollection;
    }

    @SuppressWarnings("deprecation")
    public UsuarioColeccion()  {
        db = new MongoClient().getDB("UsuariosDB");
        mongoCollection = new Jongo(db).getCollection("Usuarios");       
    }
        

    public boolean buscarUsuarioContrasena(UsuarioBean bean){ 
            String query="{_id: '"+bean.getNombreUsuario()+"'}";   
            UsuarioBean usuario = 

                 getMongoCollection().findOne(query).as(UsuarioBean.class);      
            if (usuario==null)
                return false;
            else           
                return usuario.getContraseña().equals(bean.getContraseña());
    }
}


El código del bean

UsuarioBean.java

import org.jongo.marshall.jackson.oid.Id;

@SuppressWarnings("deprecation")
public class UsuarioBean {
  
    @Id
    private String nombreUsuario;
    public String getNombreUsuario() {
        return nombreUsuario;
    }

    private String contraseña;
    public String getContraseña() {
        return contraseña;
    }

    public UsuarioBean() { }
    public UsuarioBean(String nombreUsuario, String contraseña) {
        this.nombreUsuario = nombreUsuario;
        this.contraseña = contraseña;       
    }
}
 


Se construye una prueba unitaria que no accede a la base de datos, este acceso se comprobará en las pruebas de integración. La prueba unitaria verifica que se ejecuta el método FindOne() de MongoCollection de Jongo una sola vez cuando se accede a buscar un documento en la base de datos. 

El módulo de prueba unitaria es

UsuarioColeccionTest.java

import java.net.UnknownHostException;

import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;

import org.jongo.FindOne;
import org.jongo.MongoCollection;

import estratecno.Mongo.UsuarioBean;
import estratecno.Mongo.UsuarioColeccion;

public class UsuarioColeccionTest {
   
    UsuarioColeccion coleccionUsuarios;
    UsuarioBean bean;
    MongoCollection mongoCollection;
   
    @Before
    public void before() throws UnknownHostException {
       coleccionUsuarios = new UsuarioColeccion();   
       bean = new UsuarioBean("Pepe","abcd");
       mongoCollection = Mockito.mock(MongoCollection.class);
    } 


    @Test
    public void cuandoBuscaUsuarioUsaFindOne(){
        String query="{_id: '"+bean.getNombreUsuario()+"'}";
        FindOne findResult = Mockito.mock(FindOne.class);
        Mockito.doReturn(findResult).when(mongoCollection).findOne(query);
        coleccionUsuarios.setMongoCollection(mongoCollection);
        coleccionUsuarios.buscarUsuarioContrasena(bean);       
        Mockito.verify(mongoCollection, Mockito.times(1)).findOne(query);       
    }

}
 

Asuntos remarcables del ejemplo:

  • Aunque UsuarioColección crea su propia MongoCollection en el constructor,  la prueba unitaria mockea una MongoCollection que le inyecta a UsuarioColeccion. Esta MongoCollection que suplanta a la real, permite hacer la prueba sin acceder a la Base de Datos Real. La inyección se hace con:       
        coleccionUsuarios.setMongoCollection(mongoCollection);
  • Para decirle al suplantador que la MongoCollection auténtica llama al método findOne()  se codifican las expectativas de Mockito:
        FindOne findResult = Mockito.mock(FindOne.class);
        Mockito.doReturn(findResult).when(mongoCollection).findOne(query);


         En este caso la expectativa hace uso de un suplantador de FindOne llamado findResult. 
         findResult es necesario para crear la  expectativa como  tipo  que  devuelve  el  método 
         findOne(query).
  • La forma de verificar que se llama a findOne() una sola vez es:
        Mockito.verify(mongoCollection, Mockito.times(1)).findOne(query);



 

domingo, 29 de septiembre de 2019

Pruebas software. Dobles de prueba con ejemplos (Java, Junit y Mockito)

Porqué existen dobles de pruebas


Las pruebas automatizadas son imprescindibles para el desarrollo de  software. Existen distintos tipos y niveles de pruebas. Con tipos de pruebas me refiero a: de funcionalidad, de rendimiento, de usabilidad, etc. Con niveles a: unitarias, integración, sistema, aceptación y otras más que se puedan encontrar en la literatura al respecto.

Todos los tipos y niveles de pruebas son susceptibles de automatización. No obstante tal y como indica Lisa Crispin en Los cuadrantes del testing agile unos tipos y/o niveles de pruebas son más proclives a la automatización que otros. Esto no es objetivo de este artículo.

Para explicar lo que es un doble de prueba, vamos a centrarnos inicialmente en las pruebas unitarias automatizadas. Las pruebas unitarias están ideadas para verificar que cada pequeña pieza de código que constituye un sistema, hace lo que tiene que hacer. El nombre que recibe una pieza de código depende del lenguaje de programación y de la arquitectura software que se esté utilizando. Puede ser una clase, función, método, componente, etc. Los sistemas están formados por cientos sino miles de piezas, que interactuando dan soporte a las funcionalidades del sistema. Por ello al probar una pieza estamos probando la propia pieza y todas las piezas con las que interactúa y este no es el objetivo de una prueba unitaria.

Con el objetivo de aislar una pieza del resto de las piezas con las que interactúa para probarla de forma aislada, se ideó el concepto de dobles de test.  Un doble de test es una clase específica para pruebas que sustituye a una pieza real que interacciona con la pieza que se está probando.

Para ilustrar mejor los conceptos veamos el siguiente ejemplo.

Se dispone de un sistema de gestión de pedidos que tiene 4 piezas de software. La que se quiere probar es la pieza Factura, por eso está marcada en la figura como SUT que es el acrónimo de  Subject Under Test. Se quiere hacer una prueba unitaria de Factura. Factura interacciona con las piezas Cliente y LineaFactura, además a través de LineaFactura con Producto. Para realizar una prueba unitaria podemos utilizar dobles de prueba para estas tres piezas, consiguiendo de esta forma aislar la prueba de Factura de la prueba de Cliente, Producto y LineaFactura. Esta es la misón de los dobles de prueba que suplantan a las piezas originales durante la ejecución de la prueba unitaria de Factura.

Frameworks de dobles de pruebas

Con el objetivo de poder crear dobles de prueba de la forma más sencilla para los programadores se han creado múltiples Frameworks de dobles de pruebas. Estos Frameworks en su gran mayoria están implementados de acuerdo con la corriente XUnit . Estos Frameworks la mayor parte de las veces en forma de librerías, aportan funciones que realizan los pasos: Preparar prueba, ejecutar pieza a probar, validar resultado de la ejecución.

Para aterrizar lo expuesto vamos a ver un ejemplo que usa Mockito que es un framework de dobles de prueba para java, cómo framework de pruebas para java se usa JUnit.


    01 @Test
    02 public void facturaAnadirLinea(){

    03
    04    // Preparar prueba
    05    final int CANTIDAD = 4;
    06    Producto productoMock = Mockito.mock(Producto.class);          
    07    Cliente clienteMock = Mockito.mock(Cliente.class);
    08    Factura factura = new Factura(clienteMock);
    09    LineaFactura lineaFactura = new LineaFactura(productoMock, CANTIDAD);
    10          
    11    // Ejecutar pieza a probar (SUT)
    12    factura.anadirLinea(lineaFactura);      
    13    
    14    // Validar resultado
    15    List lineas = factura.obtenerLineas();
    16    assertEquals(lineaFactura, lineas.get(0));
    17    assertEquals(lineas.size(), 1);
    18 }

   
En este ejemplo en las líneas 06 y 07 se crean objetos que no son instancias de los tipos reales. En su lugar son impostores o dobles que simulan que son los originales sin serlo. De esta forma se puede probar el método anadirLinea de Factura sin crear objetos auténticos de los tipos Producto ni Cliente. Lo mismo se podría hacer con la lineaFactura, en cuyo caso el código quedaría.

   01 @Test
   02 public void facturaAnadirLineaHayStock(){
   03    
   04     // Preparar
   05     Cliente clienteMock = Mockito.mock(Cliente.class);
   06     Factura factura = new Factura(clienteMock);
   07     LineaFactura lineaFactura = Mockito.mock(LineaFactura.class);
   08            
   09     // Ejecutar pieza a probar (SUT)
   10     factura.anadirLinea(lineaFactura);       
   11      
   12     // Validar resultado
   13     List lineas = factura.obtenerLineas();
   14     assertEquals(lineaFactura, lineas.get(0));
   15     assertEquals(lineas.size(), 1);
   16 }
   
 
En este caso, ni siquiera es necesario crear un objeto de tipo Producto, puesto que eso solo es necesario para crear objetos LineaFactura auténticos. 

Tipos de dobles de pruebas 

Ahora vamos a diferenciar los dobles de pruebas en dos tipos, unos los que permiten validar el estado y los otros los que permiten validar el comportamiento.

El ejemplo que hemos visto controla el estado del objeto. Esto es porque lo que verifica es que después de añadir una línea a una factura en la lista de líneas de factura haya al menos una línea. Esto forma parte del estado de la Factura que tiene 0, 1 o varias LineasFacturas. En este caso 1 LineaFactura.

Para entender los dobles de prueba que validan el comportamiento vamos a ver un ejemplo.
Se trata de preparar la prueba unitaria para Pedido. El pedido puede ser servido o no dependiendo de que haya unidades suficientes en el almacén. En caso de que no haya unidades se envía un correo al responsable del almacén para que reponga producto.

El código de Pedido es

01 package mocksversusstubs;
02
03 public class Pedido {
04    private ServicioCorreo pMailer;
05    private String pNombre;
06    private int pNumero;
07
08    public Pedido(String nombre, int numero, ServicioCorreo mailer){
09        pNombre = nombre;
10        pNumero = numero;
11        pMailer = mailer;
12    }
13
14    public void rellena(Almacen central){
15        if(central.tieneInventario(pNombre, pNumero)){
16            pNumero = 0;
17        }else{
18            if(null != pMailer)
19                pMailer.envia("No hay stock");
20        }
21    }
22  
23    public boolean estaRelleno(){
24        return 0 == pNumero;
25    }
26 }


El código de Almacén

01 package mocksversusstubs;
02
03 import java.util.HashMap;
04
05 public class Almacen {
06    private HashMap pCantidad =
07            new HashMap();
08
09    public boolean tieneInventario(String nombre, int numero){
10        pCantidad.put(nombre, 50);
11        int resto = tomaInventario(nombre);
12
13        if(numero <= resto){
14            pCantidad.put(nombre, resto-numero);
15            return true;
16        }
17        return false;
18    }
19
20    public void anade(String nombre, int numero){
21        pCantidad.put(nombre, numero);
22    }
23
24    public int tomaInventario(String nombre){
25        Integer resto = pCantidad.get(nombre);
26        return resto == null ? 0 : resto;
27    }
28 }


El código de ServicioCorreo

01 package mocksversusstubs;
02
03 public class ServicioCorreo {
04
05    public String envia(String str){
06        return str;
07    }
08 }


Finalmente el código de la prueba unitaria de Pedido

01 package mocksversusstubs;
02
03 import static org.junit.Assert.*;
04 import org.junit.Test;
05 import org.mockito.Mock;
06 import org.mockito.Mockito;
07
08 public class TesterDeInteraccionConPedido{
09
10    private static String TALISKER = "Talisker";
11    @Mock Almacen almacenMock;
12    @Mock ServicioCorreo emailMock;
13
14    @Test
15    public void testHacerPedidoQuitaDelInventarioSiEstaEnStock() {
16       //setup - data
17       emailMock = Mockito.mock(ServicioCorreo.class);
18       Pedido pedido = new Pedido(TALISKER, 50, emailMock);       
19       almacenMock = Mockito.mock(Almacen.class);
20       //setup - expectations
21       Mockito.when(almacenMock.tieneInventario(TALISKER, 50))
22              .thenReturn(true);
23       //exercise
24       pedido.rellena(almacenMock);
25       //verify           
26       Mockito.verify(almacenMock).tieneInventario(TALISKER, 50);
27       assertTrue(pedido.estaRelleno());
28    }
29
30    @Test
31    public void testHacerPedidoNoQuitaSiNoHaySuficienteEnStock() {
32       //setup - data
33       emailMock = Mockito.mock(ServicioCorreo.class);
34       Pedido pedido = new Pedido(TALISKER, 51, emailMock);
35       almacenMock = Mockito.mock(Almacen.class);
36       //setup - expectations
37       Mockito.when(almacenMock.tieneInventario(TALISKER, 51))
38              .thenReturn(false);
39       Mockito.when(emailMock.envia("No hay stock"))
40              .thenReturn("No hay stock");
41       //exercise
42       pedido.rellena(almacenMock);
43       //verify
44       Mockito.verify(almacenMock).tieneInventario(TALISKER, 51);
45       Mockito.verify(emailMock).envia("No hay stock");
46       assertFalse(pedido.estaRelleno());
47    }
48
49 }


En este ejemplo se utilizan dobles de prueba para los dos tipos que no se están probando, Almacén y ServicioCorreo. En la línea 21 y 22 se dice al doble de Almacén como debe comportarse cuando se invoque al método tieneInventario con los argumentos (TALISKER, 50), determinando que devuelva true para simular que de el producto TALISKER hay al menos 50 unidades. La verificación de comportamiento está en la línea 26, donde se comprueba que Pedido llama al método tieneInventario de Almacén con los argumentos (TALISKER, 50). En la línea 27 se comprueba el estado de pedido, en este caso true.

También en las líneas 44 y 45 se comprueba el comportamiento de Pedido en cuanto a que usa los métodos tieneInventario de Almacén y envia de Email. En la línea 46 se comprueba el estado de Pedido.

Conclusiones

Los dobles de prueba son de uso imprescindible para aislar la prueba unitaria de una pieza de software de las piezas con las que interacciona. 

Utilizar frameworks de pruebas ayuda a crear los dobles eliminando la necesidad de crearlos desde cero por el programador como tipos independientes que solo sirven a efectos de realizar las pruebas.

También es importante realizar el diseño de sistemas que sean testeables.  Los sistemas no testeables mediante pruebas unitarias automatizadas son más difíciles de modificar y son supceptibles de fallar puesto que las pruebas de regresión son complicadas de realizar.

Una forma de conseguir sistemas testeables es desarrollarlos con la técnica Test Driven Development (TDD), pero esa es otra historia.

miércoles, 25 de septiembre de 2019

Test Driven Development: ¡Además mejora el diseño!

Se puede escribir el código de las aplicaciones pensando que lo único importante es que se construya en el menor tiempo posible y con el menor coste. Esta forma de proceder, ha quedado patente durante los 70 años que se lleva escribiendo software, que lleva a aplicaciones que son difíciles de mantener, y el mantenimiento de las aplicaciones es, a menudo, una etapa de larga duración en el ciclo de vida de las aplicaciones.

Para que sea fácil arreglar los errores que surjan en las aplicaciones (webs, apps, microservicios, apis, etc.) es necesario que el software esté bien diseñado. Son muy peligrosos los códigos espagueti llamados así porque todo está enmarañado como en un plato de espaguetis. En estos casos los cambios de cualquier tipo son muy peligrosos porque son muy propensos a errores. Es difícil buscar errores o donde se hacen las cosas si se trata de modificar una funcionalidad. También es difícil de prever las consecuencias de modificar una parte de código, en cuanto a las consecuencias que esto tendrá en el resto del sistema.

Por todo esto la técnica de desarrollo Test Driven Development (TDD) puede venir a ayudar. TDD es una forma de desarrollo que por sus características mejora dos aspectos muy importantes del código: se tienen que construir y ejecutar constantemente las pruebas unitarias automatizadas y el diseño de los sistemas construidos mediante esta técnica tiende a ser "bueno".

Tener pruebas unitarias es bueno porque nos sirven de red de seguridad de nuestro código. Cuando cambiamos algo, podemos comprobar si las pruebas unitarias se siguen ejecutando con éxito. En caso contrario tenemos una alarma que detecta que algo en el cambio no ha ido bien.

Que el diseño sea "bueno" hace que los desarrolladores puedan comprender mejor el código y este pueda ser modificado con más versatilidad.

Existen numerosas aproximaciones para hacer buenos diseños en ingeniería del software. Hay recomendaciones generales y otras enfocadas a algún paradigma de programación en particular. Algunos consejos generales para un buen diseño son:
  • Poco acoplamiento y mucha cohesión. Dos principios fundamentales de la ingeniería del software
  • No hagas lo que no necesitas: You Ain't Gonna Need It (acrónimo YAGNI.
Para más información ver el artículo de Martin Fowler's disponible en http://martinfowler.com/bliki/Yagni.html.
  • Reutiliza el código Don't Repeat Yourself (Acrónimo DRY) 
  • Keep it simple, stupid. Keep it simple, stupid (Acrónimo KISS)
  • Algunos principios para la programación orientada a objetos son los principios SOLID. Solid es un acrónimo formado con las palabras: Single responsability, Open-Close, Liskov substitution, Interface segregation y Dependency inversion. 

Con el objetivo de demostrar que TDD es una técnica de programación que ayuda a obtener buenos diseños de código, Alex García y Viktor Farcic en su libro Test-Driven Java Development, presentan una Kata TDD basada en el juego Conecta4.

La Kata consiste en hacer dos desarrollos del mismo juego, uno sin seguir TDD y otro siguiendo esta técnica de programación. El código de ambos desarrollos se puede descargar en  https://bitbucket.org/vfarcic/tdd-java-ch05-design.git

Conecta 4 es un juego de 2 jugadores en el que se dispone de un tablero de 7 columnas por 6 filas. Los jugadores juegan por turnos introduciendo sus fichas por la parte de arriba de cada columna. Las fichas se amontonan en las columnas. Gana el jugador que consigue colocar 4 fichas de su color en línea, ya sea vertical, horizontal o diagonal. Para más datos sobre las reglas del juego https://es.wikipedia.org/wiki/Conecta_4

Analizando el código descargado de bitbucket de ambas versiones se aprecia que efectivamente el diseño es distinto. Ambas implementaciones se resuelven en una clase escrita en Java, pero los métodos difieren. Para ilustrar esto se muestran los dos figuras siguientes. Una muestra los métodos empleados en la Kata no TDD


La  otra muestra los métodos empleados en la Kata TDD

Análisis de las diferencias entre las Katas

En las figuras se muestra mediante diagrama de secuencia los métodos que tiene cada una de las clases. Las flechas a la derecha representan las llamadas entre métodos.
 
La kata TDD resuelve con 9 métodos frente a la no TDD que se resuelve con 6. Este hecho ya tiene un aroma de mejor diseño. ¿Por qué? Pues por qué esto indicar que cada método hace menos cosas y por lo tanto es más sencillo. Pero detallando más ¿Qué tiene el diseño de connect4TDD que le hace mejor que el de connect4?
  • La modularización de las funciones se ha hecho adecuadamente esto cumple el principio "single responsability". Los métodos tienen una única misión cuya funcionalidad está bien encapsulada. Por ejemplo, hay un método checkPositionToInsert() que se encarga de comprobar si hay espacio en la columna para una nueva ficha. En la versión que se hizo sin TDD este método no existía y por lo tanto esta responsabilidad estará incluida en algún método que además hará más cosas o sea tendrá más responsabilidades.
  • Los métodos que hacen menos cosas cumplen el consejo KISS-Mantén el código lo más sencillo posible. Al tener más métodos cada uno tendrá menos funcionalidades que abordar y será más sencillo.
  •  Cumple el consejo YAGNI- No lo pongas si no lo necesitas, al implementar el código tras implementar la prueba unitaria, solo se codifica lo estrictamente necesario para que la prueba se ejecute con éxito. No hay código superfluo.
  • En el conector de Connect4TDD se ha incluido un argumento tipo PrintStream para especificar cúal es el canal de salida. De esta forma si se quiere hacer uso de la clase para mostrar el tablero por un PrintStream distinto a System.out se puede hacer simplemente indicando el canal al construir el objeto de la clase Connect4TDD. Esto se puede entender cómo un desacoplamiento de Connect4TDD y el canal de salida. Sin ser exactamente inyección de dependencias, está relacionado con este principio.

Conclusiones 

Emplear la técnica TDD mejora el diseño de las aplicaciones y proporciona aplicaciones que se pueden probar de forma automatizada. 

En el canal DevOps es fundamental de disponer de pruebas automatizadas para optimizar el trabajo de los equipos de desarrollo y operaciones. Esta técnica pone pues una primera piedra para realizar mejorar que consiguen que las áreas de tecnologías de la información sean más productivas y por consiguiente más competitivas.


domingo, 22 de septiembre de 2019

Software apocalipse

Esta es mi traducción del artículo publicado en Medium como "Software Apocalipse" por James Somers en septiembre de 2017. Para mi gusto, apasionante y muy bien documentada visión de la forma en la que se actualmente se construye software.

Hubo 6 horas durante la noche del 10 de abril de 2014, en la que la población del estado de Washington no tuvo servicio del número 911. La gente que llamaba para pedir ayuda recibía la señal de ocupado. Una mujer de Seattle marcó 911 al menos 37 veces mientras un extraño estaba intentando entrar en su casa. Cuando finalmente el extraño consiguió entrar en su sala de estar por la ventana, ella cogió un cuchillo de cocina y el hombre huyó.

El apagón del 911, en ese momento el más largo nunca registrado, fue localizado en un software que estaba ejecutándose en un servidor de Englewood, Colorado. Operado por un proveedor de sistemas llamado Intrado, el servidor mantenía un contador de cuantas llamadas se habían realizado al 911 en todo el país. Los programadores de Intrado habían puesto un límite sobre la capacidad del contador. Concretamente eligieron una magnitud de millones.

Poco antes de la media noche del 10 de abril, el contador excedió esa magnitud y se produjo el caos. El contador se usaba para generar un identificador único de cada llamada, una vez excedida su capacidad se rechazaban nuevas llamadas. Los programadores no se habían anticipado al problema y no habían creado alarmas para avisar de que se iba a producir. Esto provocó que nadie entendiese lo que estaba ocurriendo. Los centros de Washington, California, Florida, Carolina, y Minnesota, que daban servicio a 11 millones de americanos, luchaban por entender porque cualquier llamada  recibía  la señal de ocupado. Hasta la mañana siguiente no se dieron cuenta que era el software de Intrado el responsable y que arreglarlo consistía solo en cambiar la capacidad del contador.

Hasta hacía poco las llamadas se gestionaban localmente. Los apagones eran pequeños y fáciles de diagnosticar y arreglar. El aumento de los teléfonos móviles y la promesa de nuevas capacidades cómo poder enviar documentos o videos al 911, condujeron a un sistema más complejo que se apoyó en internet. Por primera vez, podían producirse cosas como un apagón nacional del 911. Ahora, desde la implantación del nuevo sistema se habían producido cuatro.

Se dice que el software se está comiendo el mundo. Cada vez más sistemas críticos que hace tiempo se controlaban mecánicamente o por personas, ahora dependen de código. Esto quedo claro el verano de 2015, cuando en un solo día, United Airlines dejo a su flota en tierra porque había un problema en su sistema de gestión de salidas. O cuando se suspendieron las operaciones en la bolsa de Nueva York después de una actualización del software, también la primera página de The Wall Street Journal se cayó. El fallo simultáneo de muchos sistemas software pareció al principio un ciberataque. Casi más aterrador fue la constatación, al final del día, de que era solo una coincidencia.

"Cuando teníamos sistemas electromecánicos, solíamos revisarlos exhaustivamente” dice Nancy Leveson, que es profesora de aeronaútica y astronaútica en el MIT y ha dedicado más de 35 años a estudiar la seguridad del software. Ella se hizo conocida por su informe sobre Therac-25, una máquina de terapia de radiación que mató a seis pacientes debido a un error de software. Cuando las máquinas eran electromecánicas dice: "Solíamos ser capaces de pensar sobre todas las cosas que podía hacer, todos los estados en los que podía estar" Por ejemplo, los interbloqueos electromecánicos que controlaban los movimientos de un tren en los cruces tenían varias configuraciones que en unas pocas páginas se podían describir y se podían probar con los trenes físicamente todas para ver como se comportaban. Una vez que lo habías configurado y probado, se sabía exactamente qué pasaba con cada configuración. El problema con los sistemas software dice Levenson en su libro "es que estamos intentando construir sistemas que están más allá de nuestra capacidad intelectual".

El software es distinto. Editando un texto en alguna parte de un fichero, el mismo trozo de silicio puede convertirse en un piloto automático o en un sistema de control de inventario. Esta flexibilidad es el milagro del software y su maldición. Cómo se puede cambiar en principio a bajo precio, se cambia constantemente y cómo no tiene entidad física - un programa puede ser es mil veces más difícil que otro y ocupar el mismo espacio- tiende a complicarse sin límites.

Nuestro marco estándar para pensar sobre fallos de ingeniería - reflejados, por ejemplo, en las regulaciones para dispositivos médicos- fue desarrollado poco después de la Segunda Guerra Mundial, antes de la llegada del software, pensando en sistemas electromecánicos. La idea era hacer algo seguro haciendo sus partes seguras (es decir, construyes tu motor para soportar 40,000 ciclos de despegue y aterrizaje) y se planea algo por si las partes fallan (se construyen 2 motores). Pero el software no se rompe físicamente.  El nivel del fallo de Intrado no es como el nivel del fallo de un remache que estrella un avión. El software hizo exactamente lo que se le dijo que hiciese. De hecho lo hizo perfectamente. La razón de que fallase es que se le digo mal lo que tenía que hacer. Los fallos de software son fallos de comprensión e imaginación. Intrado actualmente tiene un router de backup al cual se hace intercambio automáticamente si hay problemas y restaura el 911 inmediatamente. Cómo se describe en un informe de la Federal Communications Commission (FCC) "la situación se produjo en la lógica de la aplicación porque no estaba diseñada para realizar acciones correctivas".

Este es el problema de hacer cosas en el software, como algo opuesto a algo físico. "La complejidad" como Levenson dice "es invisible a los ojos".

Actualmente todos los intentos en marcha para cambiar como hacemos software parecen comenzar con la misma premisa: El código es muy difícil de idear. Merece la pena intentar comprender por qué es tan extraño el código a la mente y qué lo hace tan diferente a todo lo anterior.

El progreso tecnológico ha cambiado la forma en que vemos el mundo. Hoy raramente se puede decir cuando algo se ha rehecho, porque a menudo lo que se rehace es el código. Cuando se aprieta el pie sobre el acelerador de un coche, por ejemplo, ya no se está controlando nada directamente, no hay un enlace mecánico desde el pedal al acelerador. En su lugar, se está usando una llamada a una pieza de software que decide cómo frenar. El coche es un ordenador en el que usted está sentado. El volante y los pedales son como teclas de un teclado.

Cómo todo lo demás, el coche ha sido computarizado para dotarle de nuevas características. Cuando un programa está a cargo del acelerador y los frenos, puede ralentizarlo cuando está demasiado cerca de otro automóvil, o controlar con precisión la inyección de combustible para ayudarle a ahorrar. Cuando controla el volante, puede mantener el coche en su carril si se tuerce o guiar la colocación en la plaza de aparcamiento. Estas funcionalidades no se podrían construir sin código. Si se intentara, un automóvil podría pesar 40,000 libras, una masa inamovible.

El software ha permitido que se construyan las máquinas más sofisticadas que nunca han existido. Y, sin embargo, apenas nos hemos dado cuenta, porque toda esa complejidad está empaquetada en pequeños chips de silicio con millones y millones de líneas de código. Pero el hecho de que no podamos ver la complejidad no significa que no exista.

El renombrado científico holandés especialista en informática Edsger Dijkstra escribió en 1988, "tiene que ser posible pensar en términos de jerarquías que son más profundas que las que una mente ha enfrentado hasta ahora" Con esto Dijkstra nos envió un mensaje. A medida que los programadores vertían software en sistemas críticos, se convirtieron, cada vez más, en los pilares del mundo, y Dijkstra pensó que tal vez se había sobreestimado.

Lo que hace que la programación sea tan difícil es que requiere que pensemos cómo un computador. Esto era aun más evidente en los primeros tiempos de la programación donde todo se hacía con ceros y unos. Cualquiera que mirase por encima del hombro de un programador le vería leyendo líneas cómo "100001010011” y “000010011110” , esto evidentemente está alejado de los problemas reales que intentaban resolver; viendo los ceros y unos hubiera sido imposible saber si estaban tratando de calcular trayectorias de artillería o simular un juego de tres en raya. La introducción de los lenguajes de programación cómo Fortran y C, los cuales se asemejaban al inglés y la aparición de herramientas conocidas como "Integrated Development Environments" o IDEs, que ayudan a corregir errores sencillos (cómo el chequeador gramatical de Microsoft Word pero para programas), hizo que se consiguieran mejoras, pero la mejora fue pequeña. El hecho es que los programadores siguen sin trabajar directamente sobre el problema que intentan resolver, en su lugar pasan el día escribiendo instrucciones para una máquina.

El problema es que los ingenieros de software no comprenden el problema que ellos están intentando resolver y no les importa. dice Levenson, la experta en seguridad de software del MIT. La razón es que están muy ocupados en mantener su código funcionando. "A los ingenieros del software les gusta utilizar toda clase de herramientas que les ayuden con los errores de codificación" dice Levenson en referencia a los IDEs. "Los problemas más serios que han existido en el software han tenido que ver con los requisitos no con los errores de codificación. "Cuando estás escribiendo código que controla el acelerador de un coche, por ejemplo, lo importante son las reglas sobre cuándo y cómo y por cuánto abrirlo. Pero estos sistemas han llegado a ser tan complejos que raramente alguien puede mantenerlos completos en su cabeza. "Hay 100 millones de líneas de código en los coches de hoy en día" dice Levenson "Nadie puede anticiparlo todo".

En septiembre de 2007, Jean Bookout estaba conduciendo en una autopista con su mejor amigo en un Toyota Camry cuando el acelerador pareció que se atoró. Cuando ella levantó el pie del pedal, el coche no realentizó. Entonces intentó frenó pero pareció que tampoco funcionaban. Cuando se desvió hacia una rampa de salida que iba a 50 millas por hora, apretó el freno de emergencia. El auto dejó una marca de patinaje de 150 pies de largo antes de toparse con un terraplén al costado de la carretera. El pasajero murió. Bookout despertó en un hospital un mes después.

El incidente fue uno de los muchos durante las investigaciones de casi una década sobre las reclamaciones de la llamada aceleración involuntaria en automóviles Toyota. Toyota atribuyó los incidentes a alfonbrillas mal diseñadas, pedales "pegajosos" y errores de los conductores, pero otros sospecharon que el software defectuoso podría ser el responsable. La Administración Nacional de Seguridad del Tráfico en Carreteras reclutó expertos en software de la NASA para realizar una revisión intensiva del código de Toyota. Después de casi 10 meses, el equipo de la NASA no había encontrado evidencia de que el software fuera la causa, pero dijo que no podían probar que no lo fuera.

Fué durante el litigio del accidente de Bookout que alguien encontró una conexión convincente. Michael Barr, un testigo experto en software del demandante que tenía un equipo que empleó 18 meses en el código de Toyota donde la NASA la encontró. Barr describió que encontraron "código espaguetti" que dentro de la jerga de programadores quiere decir software que se ha convertido en un lío enredado. El código se convierte en espagueti cuando se explota durante muchos años y se va modificando, amontonandose y tejiendose unas funcionalidades sobre otras alrededor de lo que ya está allí; finalmente, el código se vuelve imposible de seguir, y mucho menos probar exhaustivamente sus debilidades.

Usando el mismo modelo que el Camry que provocó el accidente, el equipo de Barr demostró que había más de 10 millones de formas para el computador de a bordo de causar aceleraciones no intencionadas. Esto demostró como el cambio de un solo bit de 0 a 1, puede llevar al coche fuera de control. El código que puso Toyota no era suficiente para parar el coche. "Hay código vigilando al código" dijo Barr "si el software no funciona bien y el mismo programa o app que esta roto se supone que tiene que arreglar el problema, no lo puede hacer porque no está funcionando".

El testimonio de Barr dió la razón al demandante, resultando en 3 millones de dólares en datos para Bookout y la familia de su amigo. De acuerdo con el New York Times, fué el primero de muchos casos similares contra Toyota por los problemas con el sistema electrónico de control del acelerador y la primera vez que un jurado declaró responsable a Toyota por un accidente provocado por una aceleración no intencionada. En total, Toyota retiró más de 9 millones de automóviles y pagó casi $3 mil millones en acuerdos y multas relacionadas con la aceleración involuntaria.

Habrá más días malos para el software. Es importante que consigamos hacerlo mejor, porque sino lo hacemos, cómo el software es cada vez más sofisticado y conectado - tomando control sobre funciones cada vez más críticas - cada vez los problemas serán peores.

El problema es que los programadores están teniendo momentos difíciles para mantener su propio código. Desde 1980, la forma en que los programadores trabajan y las herramientas que usan han cambiado muy poco. Hay un grupo pequeño pero creciente que opina que esto es insostenible. "Hasta los muy buenos programadores luchan para dar sentido a los sistemas con los que trabajan" dice Chris Granger, un desarrollador de software que trabaja como jefe de Microsoft Visual Studio, un IDE que cuesta 1,199$ al año y es usado por cerca de la tercera parte de los programadores profesionales. Él me dijo que mientras estaba en Microsoft, realizó un estudio completo de Visula Studio, el más completo que nunca se había hecho. Durante un mes y medio, el miró como la gente escribía el código. "¿Cómo usaban las herramientas? ¿Cómo pensaban?" dijo. "¿Como se sientan frente a su ordenador, tocan el ratón o no? Todas estas cosas sobre las que tenemos una creencia pero no hemos visto en la realidad.

Los hallazgos le sorprendieron. "Visual Studio es una de las herramientas software más grandes del mundo" el dijo. "Tiene unos 55 millones de líneas de código. Y una de las cosas que descubrí es que más del 90% de las líneas son totalmente irrelevantes. Se realizó mucho trabajo pero faltaban cosas para los problemas mas importantes con los que se enfrenta la gente. Y el descubrimiento más grande que me llevé es que la gente intenta emular a la computadora dentro de su cabeza" Los programadores son como jugadores de ajedrez intentando jugar con una venda, de tal manera que la mayor parte de su energía mental se gasta en intentar imaginar donde están las piezas más que pensar en el juego en sí.

John Resig ha notado lo mismo entre sus estudiantes. Resig es un famoso programador de JavaScript - El software que escribió se usa en la mitad de los website existentes - y es un lider tecnológico en el sitio de formación on-line Khan Academy. A principios de 2012, el ha estado luchando con el plan de estudios del sitio. ¿Porqué es tan difícil aprender a programar? El principal problema parece ser que el código es muy abstracto. Escribir software no es como hacer un puente con palitos de helados, donde puedes ver los palos y tocar el pegamento. Para "hacer" un programa  se escriben palabras. Cuando se quiere cambiar el comportamiento del programa, ya sea un juego o un website o una simulación de física, lo que hay que cambiar es texto. Por eso los estudiantes que lo consiguen - de hecho los únicos que sobreviven - son aquellos que van paso a paso sobre el texto siguiendo la pista de los calculos intermedios. Resig, al igual que Granger, empezaron a preguntarse si eso tiene que ser de esa forma. Los ordenadores tienen el doble de poder cada 18 meses en los últimos 40 años. ¿Porqué no ha cambiado la forma de programar?.

El hecho de que los dos estaban pensando sobre el mismo problema, en los mismos términos y en el mismo momento no era una coincidencia. Ellos habían asistido a una charla,dada a un grupo de estudiantes de ingeniería del software en un hotel de Montreal por un investigador llamado Bret Victor. La charla, que se hizo viral cuando se publicó online en febrero de 2012, hacía dos remarcadas quejas. La primera era que la forma en que hacemos software está desfasada. La segunda que Victor sabía como arreglar el problema.

A Bret Victor no le gustaba escribir código. "Suena raro", dice. “Cuando quiero hacer algo, especialmente cuando quiero crear algo en software, hay una capa inicial de disgusto que tengo que atravesar, donde realmente no estoy manipulando lo que quiero hacer, estoy escribiendo un montón de texto en un editor de texto ".

"Hay una fuerte convicción que es que esta es la manera de hacer las cosas mal".

Victor tiene el semblante de David Foster Wallace, con una inteligencia relámpago que perdura bajo una pátina de timidez. Tiene 40 años, canoso y una pequeña barba no dejada a posta. Su voz es suave, casi lúgubre, pero quiere compartir lo que está en su cabeza, y cuando se pone en marcha parece saltarse las sílabas, como si estuviera dejando atrás su propia voz.

Aunque él lleva un laboratorio que estudia el futuro de los ordenadores, parece menos interasado en tecnología que en la gente que la usa. Cómo un buen constructor de herramientas, tiene una forma de mirar el mundo que es a partes iguales técnica y humana. Se graduó el primero de su promoción en el Instituto de Tecnología de California, en ingeniería electrica, y se fué a trabajar a una compañia que desarrollaba sintetizadores de música. Este era un problema que se ajustaba perfectamente a su doble personalidad. El podía gastar mucho tiempo pensando la forma en que los musicos usaban el teclado - llegando a ser una extensión de sus manos - así como pensar sobre la parte matemática del proceso de la señal digital.

En los tiempos en que daba la charla que hizo su nombre, la misma que oyeron Resig y Granger en 2012, Victor había aterrizado el principio que parecía que enebraría todo su trabajo. (A la charla la llamó  "Inventing on Principle."). El principio era que: los creadores necesitan conexión inmediata con lo que están creando". El problema es que en programación este principio se viola. Esto es lo que provoca que los sistemas sean tan duros de idear y tan propensos a errores. El programador, mirando a una página de texto,debe abstraerse sobre lo que esté haciendo.

"Nuestra concepción de que es un programa de computador es" , el dijo, esta " directamente derivada de Fortran y Algol en los finales de los 50. Aquellos lenguajes estaba diseñados para tarjetas perforadas" Ese código ahora toma la forma de una carta en una pantalla en un lenguaje como C o Java en lugar de un monton de tarjetas con agujeros, no deja de ser menos anticuado ni menos directo.

Hay una analogía con los procesadores de texto. En los procesadores anteriores usted podía ver el texto y para configurar el diseño o las fuentes o los márgenes, tenía que escribir caracteres especiales "códigos de control" o comandos que le decían al ordenador por ejemplo: "esta parte de texto va en italics". El problema era que usted no podía ver el efecto de estos códigos hasta que no imprimía el documento. Era difícil predecir lo que ibas a obtener. Tenías que imaginar cómo el ordenador iba a interpretar los código, es decir tenía que jugar a, con su cabeza, interpretar lo que iba a hacer el ordenador.

Entonces apareció el concepto WYSIWYG. Significa "Lo que ves es lo que obtienes". Cuando marcabas un pasaje en cursiva, las letras se inclinaban allí mismo en la pantalla. Si quiere cambiar el margen, puede arrastrar una regla en la parte superior de la pantalla y ver el efecto de ese cambio. De este modo, el documento se mostraba como era, y se formateaba haciendo clic aquí y alla. Con solo mirar, sabías  habías hecho algo mal. El control de un sistema sofisticado, para diseñar el formato del documento, estaba disponible para cualquiera que pudiera hacer clic en una página.

El punto de vista de Victor era que la programación en sí se podría hacer así. Para él, la idea de que las personas estaban construyendo software para cosas importantes, como diseñar sistemas adaptativos de control de crucero para aviones o tratar de entender el cáncer, que lo tuviesen que hacer mirando a un editor de texto, era espantoso. Y era el trabajo de los programadores asegurar que algún día no tuvieran que hacerlo.

Había precedentes que sugerían que no era una idea de locos. Photoshop, por ejemplo, ponía a disposición de los usuarios poderosos algoritmos de procesamiento de imágenes aunque ellos no supiesen ni lo que era un algoritmo. Es una pieza de software compleja, en el buen sentido de la palabra, con perillas, botones y controles deslizantes que el usuario aprende a tocar como un instrumento. Squarespace, una compañía que es quizás la mejor conocida por anunciarse agresivamente en podcast, hace herramientas que permiten a los usuarios construir websites haciendo clic, en lugar de escribir código HTML y CSS. Es suficiente poderosa para hacer el trabajo que podría haber sido hecho por un diseñador web profesional.

Pero estos son solo algunos de ejemplos. La abrumadora realidad es que cuando alguien quiere hacer algo comlejo con un ordenador, tiene que escribir código. Victor que es algo idealista, pensó que esto era motivo de bajar la moral de los programadores. Su charla era una llamada a las armas.

En el corazón de todo esto había una serie de demos que mostraban cómo de primitivas eran las herramientas actuales para distintos problemas - diseño de circuitos, animación por computadora, algoritmos de debuggimg - y como se veían las mejores. Sus demos eran virtuosas. El que más llamó la atención fué el que a primera vista era más trivial. Mostraba una pantalla dividida con un juego que se parecía a Mario en un lado y el código que lo controlaba en el otro. Cuando Victor cambiaba el código, las cosas en el mundo del juego cambiaban: disminuyó un número correspondiente a la fuerza de la gravedad y el personaje de Mario flotó; aumentó otra, la velocidad del jugador, y Mario corrió por la pantalla.

Suponga que quiere diseñar un nivel donde Mario, salta y rebota en una tortuga, simplemente lo convertiría en un pequeño pasillo. Los programadores de juegos resuelven esto en dos pasos: primero se concentran en el código - El código que controla cómo salta Mario, cómo de rápido corre, cuán hinchable estaba la espalda de la tortuga - y hacen agunos cambios en el editor de texto, usando su imaginación para predecir el efecto que estos tendrán. Entonces, relanzan el juego para ver lo que ocurre.

Victor quería algo más inmediato. "Si tu tienes un proceso a tiempo" el dijo , refiriendose al camino de Mario mediante el nivel, "y quires ver los cambios inmediatamente, tiene que trazar el mapa tiempo a espacio" El apretaba un boton que mostraba no solo donde estaba ahora Mario sino también donde estaría en cada momento en el futuro: una curva se sombras de Mario estirandose en la distancia.

Además, esta curva proyectada era reactiva: cuando Victor cambiaba los parámetros del juego,  controlandolos por un rápido arrastre del mouse, la forma de la curva cambiaba. Era como tener una vista del juego a los ojos de Dios. Todo el problema se había reducido a jugar con diferentes parámetros, como si se ajustaran los niveles en un receptor estéreo, hasta conseguías que Mario pasaba la aguja. Con la interfaz correcta, era casi como si no estuvieras trabajando con código en absoluto; estabas manipulando el comportamiento del juego directamente.

Cuando la audiencia vió esta acción, quedaron con los ojos abiertos. Sabían que no esto que estaba viendo no era un juego de niños, sino más bien el futuro de la industria. La mayoría del software involucraba comportamientos que se desarrollaban, de manera compleja en su relación con el tiempo, y Victor había demostrado que si se era lo suficientemente imaginativo, se podían desarrollar formas de ver cambiar ese comportamiento, como si estuviera jugando con él en sus manos. Un programador que vio la charla escribió más tarde: "De repente, todas mis herramientas me parecen obsoletas".

Cuando Hohn Resig vio la charla, él cambió sus planes para el plan de estudios de la Khan Academy. Él quería que los ejercicios de los programadores fuesen como las demos de Victor. En el lado izquierdo tenián el código y en el derecho una imagen del juego que estaban programando. Si se cambiaba el código la imagen cambiaba inmediatamente. "En un entorno que es verdaderamente receptivo", escribió Resig sobre el enfoque, "cambia completamente el modelo de cómo aprende un estudiante ... [Ellos] ahora ven inmediatamente el resultado e intuyen cómo funcionan inherentemente los sistemas subyacentes sin siquiera seguir una explicación explicita”. Khan Academy se ha convertido quizás en la clase de programación de computadoras más grande del mundo, con un millón de estudiantes, en promedio, que utilizan activamente el programa.

Chris Granger, que había trabajado en Microsoft en Visual Studio, también se inspiró. A los pocos días de ver un video de la charla de Victor, en enero de 2012, construyó un prototipo de un nuevo entorno de programación. Su capacidad clave era que le proporcionaría comentarios instantáneos sobre el comportamiento del programa. Vería lo que estaba haciendo su sistema justo al lado del código que lo controlaba. Fue como quitarse una venda en los ojos. Granger llamó al proyecto "Mesa de luz".

En abril de 2012, buscó fondos para Light Table en Kickstarter. En los círculos de programación, fue una sensación. En un mes, el proyecto recaudó más de $200,000. Las ideas se difundieron. El concepto de poder ver los datos que fluyen a través del programa al instante, se abrió paso en las herramientas de programación insignia ofrecidas por Google y Apple. Apple desarrolló el lenguaje predeterminado para crear nuevas aplicaciones para iPhone y Mac, llamado Swift, desde cero para soportar un entorno, llamado Playgrounds, que se inspiró directamente en Light Table.

Pero al ver el impacto que su charla terminó teniendo, Bret Victor se desilusionó. "Había muchas  interpretaciones erróneas de lo que estaba diciendo", dijo más tarde. Sabía que algo andaba mal cuando la gente comenzó a invitarlo a conferencias para hablar sobre herramientas de programación. "Todos pensaban que estaba interesado en los entornos de programación", dijo. Realmente estaba interesado en cómo las personas ven y entienden los sistemas, como él lo expresa, en la "representación visual del comportamiento dinámico". Aunque el código se había convertido en la herramienta elegida para crear un comportamiento dinámico, seguía siendo una de las peores herramientas para comprender eso. El objetivo de “Inventing on Principle” era mostrar que se podía mitigar el problema haciendo que la conexión entre el comportamiento de un sistema y su código sea inmediata.

En un par de charlas posteriores, "Stop Drawing Dead Fish" y "Drawing Dynamic Visualizations", Victor fue más allá. Demostró dos programas que había creado, el primero para animadores, el segundo para científicos que intentaban visualizar sus datos, cada uno de los cuales normalmente consistía en un proceso que solía involucrar escribir mucho código personalizado y los redujo a jugar en una interfaz WYSIWYG. Víctor sugirió que se podría hacer el mismo truco para casi todos los problemas donde se estaba escribiendo código actualmente. "No estoy seguro de que la programación tenga que existir", me dijo. "O al menos los desarrolladores de software". En su opinión, el rol apropiado de un desarrollador de software era crear herramientas que eliminaran la necesidad de desarrolladores de software. Solo entonces las personas con problemas que necesitan computación serían capaces de enfrentarlos directamente sin tener que hacerlo a través del código.

Por supuesto, para hacer eso, los programadores tendrían que estar de acuerdo. En un ensayo reciente, Victor imploró a los desarrolladores de software profesionales que dejaran de poner su talento en herramientas para crear aplicaciones como Snapchat y Uber. "Los asuntos de la vida diaria no son los problemas importantes", escribió. En cambio, deberían centrarse en los problemas científicos e ingenieriles, como él me dijo, "estas personas que están haciendo un trabajo que realmente importa, y que es crítico, y que utilizan herramientas muy, muy malas". Un trabajo interesante de este tipo, son las herramientas para el "diseño basado en modelos" que ya estaba en marcha, escribió, y lo había estado durante años, pero la mayoría de los programadores no sabían nada al respecto.

"Si realmente miras detenidamente todos los productos industriales que están en el mercado y que estás usando, que las compañías están usando, lo único que tienes es el código". Eric Bantégnie es el fundador de Esterel Technologies (ahora propiedad de ANSYS), una compañía francesa que fabrica herramientas para construir software crítico para la seguridad. Al igual que Victor, Bantégnie no cree que los ingenieros deban desarrollar grandes sistemas escribiendo millones de líneas de código en un IDE. "Nadie construiría un automóvil a mano", dice. “El código sigue siendo, en muchos lugares, artesanía. Cuando se crean manualmente 10.000 líneas de código, puede valer. Pero tiene sistemas que tienen 30 millones de líneas de código, como un Airbus, o 100 millones de líneas de código, como Tesla en sus autos de alta gama, el software se está volviendo muy, muy complicado ".

La compañía de Bantégnie es una de las pioneras en el uso industrial del diseño basado en modelos, en el que ya no escribe código directamente. En su lugar, crea un tipo de diagrama de flujo que describe las reglas que su programa debe seguir (el "modelo"), y la computadora genera un código para usted basado en esas reglas. Si se hace el sistema de control para un elevador, por ejemplo, una regla podría ser que cuando la puerta está abierta y alguien presiona el botón del vestíbulo, debe cerrar la puerta y comenzar a mover el ascensor. En una herramienta de diseño basada en modelos, representaría esta regla con un pequeño diagrama, como si dibujara la lógica en una pizarra, hecha de cajas que representan diferentes estados, como "puerta abierta", "en movimiento" y "puerta cerrado "- y líneas que definen cómo puede pasar de un estado a otro. Los diagramas hacen obvias las reglas del sistema: con solo mirar, puede ver que la única forma de hacer que el elevador se mueva es cerrar la puerta, o que la única manera de abrir la puerta es detenerse.

Esto no es exactamente cómo Photoshop. La belleza de Photoshop, por supuesto, es que la imagen que estás manipulando en la pantalla es el producto final. En el diseño basado en modelos, por el contrario, la imagen en su pantalla es más como un plano. Aún así, hacer que el software de esta manera es cualitativamente diferente de la programación tradicional. En la programación tradicional, su tarea es tomar reglas complejas y traducirlas a código; la mayor parte de su energía se gasta haciendo la traducción, en lugar de pensar en las reglas mismas. En el enfoque basado en modelos, todo lo que tiene son las reglas. Eso es en lo que pasas el tiempo pensando. Es una forma de enfocarse menos en la máquina y más en el problema que está tratando de resolver.

"Normalmente, el principal problema con la codificación de software, y yo mismo soy un programador", dice Bantégnie, "no son las habilidades de los programadores. La gente sabe codificar. El problema es qué codificar. Debido a que la mayoría de los requisitos son un tipo de lenguaje natural que es ambiguo, un requisito nunca es extremadamente preciso, y el tipo que codifica a menudo lo entiende de manera diferente a cómo lo entiende el que lo formuló".

Desde este punto de vista, el software se vuelve complicado porque los medios para describir lo que debe hacer el software (conversaciones, descripciones en prosa, dibujos en una hoja de papel) son muy diferentes de los medios que describen lo que hace el software, es decir, el propio código. Se pierde demasiado yendo de uno a otro. La idea detrás del diseño basado en modelos es cerrar la brecha. Los diseñadores del sistema utilizan el mismo modelo para expresar lo que quieren y para construirlo. En base al modelo la computadora genera automáticamente el código.

Por supuesto, para que este enfoque tenga éxito, mucho del trabajo debe hacerse antes de que el proyecto comience. Primero alguien tiene que construir una herramienta para desarrollar modelos que sean entendibles para las personas, que sean como las notas y los dibujos que harían ellos mismos, sin dejar de ser lo suficientemente inequívocos para que una computadora los entienda. Tienen que hacer un programa que convierta estos modelos en código real. Y finalmente tienen que demostrar que el código generado hace lo que debe hacer. "Nos hemos beneficiado de afortunadamente 20 años de experiencia", dice Bantégnie.

Esterel Technologies, que fue adquirido por ANSYS en 2012, surgió de la investigación iniciada en la década de 1980 por las industrias nucleares y aeroespaciales francesas, a quienes les preocupaba que a medida que el código crítico para la seguridad aumentara en complejidad, cada vez era más difícil mantenerlo libre de error. "Comencé en 1988", dice Emmanuel Ledinot, director de estudios científicos de Dassault Aviation, un fabricante francés de aviones de combate y aviones comerciales. “En ese momento, estaba trabajando en sistemas de aviónica militar. Y las personas a cargo de integrar los sistemas y depurarlos notaron que la cantidad de errores aumentaba ”. Los años 80 vieron un aumento en la cantidad de computadoras a bordo en los aviones. En lugar de una sola computadora de vuelo, ahora había docenas, cada una responsable de tareas altamente especializadas relacionadas con el control, la navegación y las comunicaciones. La coordinación de estos sistemas para volar el avión a medida que los datos llegaban desde los sensores y los pilotos ejecutaban comandos requería un conjunto de reacciones perfectamente sincronizadas. "El manejo de estos cientos e incluso miles de posibles eventos en el orden correcto, en el momento correcto", dice Ledinot, "fue diagnosticado como la causa principal del crecimiento de errores".  

Ledinot decidió que escribir este código tan complicado a mano ya no era sostenible. Era demasiado difícil entender lo que se estaba haciendo, y casi imposible verificar que funcionaría correctamente. Pensó en algo nuevo. "Cambiar las herramientas es extremadamente costoso en un proceso como este", dijo en una charla. "No tomas este tipo de decisión a menos que estés entre la espada y la pared".

Comenzó a colaborar con Gerard Berry, un científico informático en INRIA, el centro francés de investigación informática, en una herramienta llamada Esterel, un acrónimo del francés en "tiempo real". La idea detrás de Esterel era que, si bien los lenguajes de programación tradicionales podrían ser buenos para describir procedimientos simples que ocurrían en un orden predeterminado, como una receta, si tratas de usarlos en sistemas donde pueden ocurrir muchos eventos en casi cualquier momento, en casi cualquier orden, como en la cabina de un avión, inevitablemente es un desastre. Y un desastre en el software de control era peligroso. En un artículo, Berry fue tan lejos como para predecir que "las técnicas de programación de bajo nivel no serán aceptables para grandes programas críticos de seguridad, ya que hacen que la comprensión y el análisis del comportamiento sean casi impracticables".

Esterel fue diseñado para que la computadora maneje esta complejidad por usted. Esa era la promesa del enfoque basado en el modelo: en lugar de escribir un código de programación normal, creó un modelo del comportamiento del sistema; en este caso, un modelo centrado en cómo deben manejarse los eventos individuales, cómo priorizar los eventos, qué eventos dependían en el que otros, y así sucesivamente. El modelo se convierte en el plan detallado que la computadora usaría para hacer la programación real.

Ledinot y Berry trabajaron durante casi 10 años para llevar a Esterel al punto en que podría usarse en entornos  productivos. "Fue en 2002 que tuvimos el primer entorno de modelado de software operativo con generación automática de código", dijo Ledinot, "y el primer módulo integrado en Rafale, el avión de combate". Hoy, la familia de productos ANSYS SCADE (para "seguridad" en entornos de desarrollo de aplicaciones críticas") es utilizado para generar código por compañías en las industrias aeroespacial y de defensa, en plantas de energía nuclear, sistemas de tránsito, industria pesada y dispositivos médicos. "Mi sueño inicial era tener código generado por SCADE en cada avión del mundo", dice Bantégnie, el fundador de Esterel Technologies, "y no estamos muy lejos de ese objetivo". Casi todo el código crítico para la seguridad en El Airbus A380, incluido el sistema que controla las superficies de vuelo del avión, se generó con los productos ANSYS SCADE.

Parte del atractivo para los clientes, especialmente en la aviación, es que si bien es posible construir software altamente confiable a mano, puede ser un esfuerzo hercúleo. Ravi Shivappa, vicepresidente de ingeniería de software del grupo en Meggitt PLC, un cliente de ANSYS que fabrica componentes para aviones, como detectores de incendios neumáticos para motores, explica que los proyectos tradicionales comienzan con un documento de requisitos masivos en inglés, que especifica todo lo que el software debe hacer. (Un requisito podría ser algo así como: "Cuando la presión en esta sección se eleva por encima de un umbral, abra la válvula de seguridad, a menos que el interruptor de anulación manual esté activado"). El problema al describir los requisitos de esta manera es que cuando implementa en el código, debe verificar minuciosamente que cada uno esté satisfecho. Y cuando el cliente cambia los requisitos, el código también debe cambiarse y probarse exhaustivamente para asegurarse de que no se haya roto nada más en el proceso.

El costo se agrava por los exigentes estándares regulatorios. La FAA es fanática de la seguridad del software. La agencia exige que todos los requisitos para una pieza de software crítico para la seguridad se puedan rastrear todas las líneas de código que lo implementan, y viceversa. Por lo tanto, cada vez que cambia una línea de código, debe volver sobre el requisito correspondiente en el documento de diseño, y debe poder demostrar que el código realmente cumple el requisito. La idea es que si algo sale mal, puedes descubrir por qué; la práctica aporta orden y responsabilidad a las grandes bases de código. Pero, dice Shivappa, "es un proceso que requiere mucha mano de obra". Estima que antes de que usaran un diseño basado en modelos, en un proyecto de dos años solo se gastaban dos o tres meses en escribir el código; el resto se gastaba trabajando en la documentación.

Como explica Bantégnie, la grandeza de tener una computadora que convierta sus requisitos en código, en lugar de un ser humano, es que puede estar seguro, de hecho, puede demostrar matemáticamente, que el código generado realmente satisface esos requisitos. Gran parte del beneficio del enfoque basado en el modelo proviene de poder agregar requisitos sobre la marcha sin dejar de garantizar que se cumplan los existentes; con cada cambio, la computadora puede verificar que su programa aún funciona. Usted es libre de modificar su plan sin temor a introducir nuevos errores. Su código es, en lenguaje de la FAA, "correcto por construcción".

Aún así, la mayoría del software, incluso en el mundo de la aviación obsesionado con la seguridad, se hace a la antigua, con ingenieros que escriben sus requisitos en prosa y los programadores los codifican en un lenguaje de programación como C. Como Bret Victor dejó claro en su ensayo , el diseño basado en modelos es relativamente inusual. "Mucha gente en la FAA cree que la generación de código es mágica y, por lo tanto, exige un mayor escrutinio", me dijo Shivappa.

La mayoría de los programadores sienten lo mismo. A ellos les gusta el código. Al menos lo entienden. Las herramientas que escriben su código por usted y verifican su corrección utilizando las matemáticas de "máquinas de estado finito" y "sistemas recurrentes" suenan esotéricas y difíciles de usar, si no demasiado buenas para ser verdad.

Es un patrón que se ha desarrollado antes. Cada vez que la programación se aleja de la escritura de ceros y unos, las objeciones más fuertes provienen de los programadores. Margaret Hamilton, una célebre ingeniera de software en las misiones Apolo, de hecho, la creadora de la frase "ingeniería de software", me dijo que durante su primer año en el laboratorio Draper en el MIT, en 1964, recuerda una reunión en la que una facción estaba luchando con otra sobre la transición de "un lenguaje de máquina de bajo nivel", al "lenguaje ensamblador". "La gente que defendía el lenguaje de bajo nivel decía: "Bueno, ¿cómo sabemos que el lenguaje ensamblador lo hará bien?"

Emmanuel Ledinot, de Dassault Aviation, señaló que cuando el lenguaje ensamblador se eliminó gradualmente a favor de los lenguajes de programación que todavía son populares hoy, como C, fueron los programadores de ensamblador los que se mostraron escépticos esta vez. Entonces no es de extrañar, dijo, que "las personas no estén haciendo la transición tan fácilmente al desarrollo de software basado en modelos: lo perciben como otra oportunidad para perder el control, incluso más de lo que ya lo han hecho".

El sesgo contra el diseño basado en modelos, a veces conocido como ingeniería dirigida por modelos, o MDE, de hecho está tan arraigado que, según un artículo reciente, "algunos incluso argumentan que existe una mayor necesidad de investigar la percepción de MDE de las personas que de investigar nuevas tecnologías MDE ". Para los defensores del enfoque basado en modelos, suena casi como una broma: ya sabemos cómo hacer que el software complejo sea confiable, pero en muchos lugares, estamos eligiendo no hacerlo. ¿Por qué?

En 2011, Chris Newcombe había trabajado en Amazon durante casi siete años, y se había convertido en ingeniero principal. Había trabajado en algunos de los sistemas más críticos de la compañía, incluido el catálogo de productos minoristas y la infraestructura que administraba todos los dispositivos Kindle del mundo. Fue líder en el equipo de Amazon Web Services, muy apreciado, que mantiene servidores en la nube para algunas de las propiedades más grandes de la web, como Netflix, Pinterest y Reddit. Antes de Amazon, había ayudado a construir la columna vertebral de Steam, el servicio de juegos en línea más grande del mundo. Es uno de esos ingenieros cuyo trabajo mantiene en silencio el funcionamiento de Internet. Los productos en los que había trabajado fueron considerados éxitos masivos. Pero lo único en lo que podía pensar era en que enterrados profundamente en los diseños de esos sistemas había desastres esperando a suceder.

"La intuición humana es pobre para estimar la probabilidad real de combinaciones de eventos en sistemas que operan a una escala de millones de solicitudes por segundo", escribió en un documento. “Esa falibilidad humana significa que algunos de los errores más sutiles y peligrosos resultan ser errores de diseño; el código implementa fielmente el diseño previsto, pero el diseño no puede manejar correctamente un escenario "raro y particular ".

Newcombe estaba convencido de que los algoritmos detrás de los sistemas verdaderamente críticos (sistemas que almacenan una porción significativa de los datos de la web, por ejemplo) no deberían ser solo buenos, sino perfectos. Un solo error sutil podría ser catastrófico. Pero sabía lo difícil que eran encontrar errores, especialmente a medida que un algoritmo se volvía más complejo. Podrías hacer todas las pruebas que quisieras y nunca las encontrarías.

Es por eso que estaba tan intrigado cuando, en el apéndice de un artículo que había estado leyendo, se encontró con una extraña mezcla de matemáticas y código, o lo que parecía un código, que describía un algoritmo en algo llamado "TLA+". Lo sorprendente fue que se dijo que esta descripción era matemáticamente precisa: un algoritmo escrito en TLA+ podría en principio ser correcto. En la práctica, le permitió crear un modelo realista de su problema y no solo probarlo, sino probarlo exhaustivamente. Esto era exactamente lo que había estado buscando: un lenguaje para escribir algoritmos perfectos.

TLA+, que significa "Lógica temporal de acciones", es similar en espíritu al diseño basado en modelos: es un lenguaje para escribir los requisitos (TLA+ los llama "especificaciones") de los programas de computadora. Estas especificaciones pueden ser verificadas completamente por una computadora. Es decir, antes de escribir cualquier código, escriba un esquema conciso de la lógica de su programa, junto con las restricciones que necesita para satisfacer (por ejemplo, si estuviera programando un cajero automático, una restricción podría ser que nunca podrá retirar el mismo dinero dos veces desde su cuenta corriente). TLA+ luego verifica exhaustivamente que su lógica, de hecho, satisface esas restricciones. De lo contrario, le mostrará exactamente cómo podrían violarse.

El lenguaje fue inventado por Leslie Lamport, un científico informático ganador del Premio Turing. Con una gran barba blanca y cabello blanco desaliñado, y ojos amables detrás de grandes anteojos, Lamport parece que podría ser uno de los profesores más amigables en el Hogwarts estadounidense. Ahora en Microsoft Research, es conocido como uno de los pioneros de la teoría de los "sistemas distribuidos", que describe cualquier sistema informático compuesto de múltiples partes que se comunican entre sí. El trabajo de Lamport sentó las bases para muchos de los sistemas que impulsan la web moderna.

Para Lamport, una de las principales razones por las que el software de hoy está tan lleno de errores es que los programadores saltan directamente a escribir código. "Los arquitectos dibujan planos detallados antes de colocar un ladrillo o clavar un clavo", escribió en un artículo. "Pero pocos programadores escriben un esbozo de lo que harán sus programas antes de comenzar a codificar". Los programadores se sienten atraídos por la esencia de la codificación porque el código es lo que hace que los programas funcionen; pasar tiempo en cualquier otra cosa puede parecer una distracción. Y hay una alegría paciente, un tipo de satisfacción meditativa, que se puede tener al descifrar la micromecánica del código. Pero el código, argumenta Lamport, nunca fue un medio para pensar. "Realmente cuando estás pensando en términos de un lenguaje de programación, eso limita tu capacidad de pensar ", dice. El código hace que los árboles no te dejen ver el bosque, ya que llama tu atención sobre piezas individuales, en lugar de la imagen más amplia de cómo encaja tu programa, o qué se supone que debe hacer, y si realmente hace lo que piensas. Es por eso que Lamport creó TLA+. Al igual que con el diseño basado en modelos, TLA+ centra su atención en la estructura de alto nivel de un sistema, su lógica esencial, más que en el código que lo implementa.

Newcombe y sus colegas en Amazon continuarían usando TLA+ para encontrar errores sutiles y críticos en los sistemas principales, incluidos los errores en los algoritmos centrales detrás de S3, considerado quizás el motor de almacenamiento más confiable del mundo. Ahora se usa ampliamente en la empresa. En el pequeño universo de personas que alguna vez habían usado TLA+, su éxito no fue tan inusual. Un pasante en Microsoft usó TLA+ para detectar un error que podría haber causado que todas las Xbox del mundo se bloqueen después de cuatro horas de uso. Los ingenieros de la Agencia Espacial Europea lo utilizaron para reescribir, con 10 veces menos código, el sistema operativo de una sonda que fue la primera en aterrizar suavemente en un cometa. Intel lo usa regularmente para verificar sus chips.

Pero TLA+ ocupa solo un pequeño y lejano rincón de la corriente principal, si se puede decir que ocupa algún espacio allí. Incluso para un ingeniero experimentado como Newcombe, el lenguaje se leía al principio como extraño y esotérico: un zoológico de símbolos. Para Lamport, esto es un fracaso de la formación de los programadores. Aunque la programación nació en las matemáticas, desde entonces se ha divo            rciado de ella. La mayoría de los programadores no son muy fluidos en el tipo de matemática (lógica y teoría de conjuntos, en su mayoría) que necesita para trabajar con TLA+. “Muy pocos programadores, e incluidos muy pocos maestros de programación, entienden los conceptos más básicos y cómo se aplican en la práctica. Y parecen pensar que todo lo que necesitan es código ”, dice Lamport. "La idea de que hay un nivel más alto que el código que necesitas entender, y que las matemáticas realmente te permiten entenderlo, es completamente deshechada. Porque nunca lo aprendieron ".

En pocas palabras, Lamport considera que esta incapacidad para pensar matemáticamente sobre lo que están haciendo es el problema del desarrollo de software moderno: las apuestas siguen aumentando, pero los programadores no están avanzando, no han desarrollado las habilidades necesarias para manejar problemas cada vez más complejos . "En el siglo XV", dijo, "la gente solía construir catedrales sin conocer el cálculo, y hoy en día no creo que permitas que nadie construya una catedral sin conocer el cálculo. Y espero que después de un período de tiempo adecuadamente largo, a las personas no se les permita escribir programas si no entienden estas cosas ".

Newcombe no está tan seguro de que el culpable sea el programador. "He oído de Leslie que él piensa que los programadores tienen miedo de las matemáticas. Descubrí que los programadores no son conscientes, o no creen, que las matemáticas pueden ayudarlos a manejar la complejidad. La complejidad es el mayor desafío para los programadores ". El verdadero problema para lograr que las personas usen TLA+, dijo, fue convencerlos de que no sería una pérdida de tiempo. Los programadores, como especie, son implacablemente pragmáticos. Herramientas como TLA+ apestan a la torre de marfil. Cuando los programadores encuentran "métodos formales" (llamados así porque involucran descripciones matemáticas, "formalmente" precisas de programas), su instinto profundo es echarse atrás.

La mayoría de los programadores que estudiaron ciencias de la computación en la universidad han estudiado brevemente métodos formales. Por lo general, se demuestran en algo trivial, como en un programa que cuenta desde cero; el trabajo del alumno es demostrar matemáticamente que el programa, de hecho, cuenta desde cero.

"Necesitaba cambiar las percepciones de las personas sobre los métodos formales", me dijo Newcombe. Incluso el propio Lamport no pareció comprender completamente este punto: los métodos formales tenían un problema de imagen. Y la forma de solucionarlo no era implorar a los programadores que cambiaran, era cambiar usted mismo. Newcombe se dio cuenta de que para llevar herramientas como TLA+ a la corriente principal de programación, tenía que comenzar a hablar su idioma.

Por un lado, dijo que cuando presentara a TLA+ a sus colegas de Amazon evitaría decirles lo que significaba, porque temía que el nombre lo hiciera parecer innecesariamente prohibitivo: "La lógica temporal de las acciones" tiene exactamente el tipo de fallas. suena a eso que funciona bien en la academia, pero desanima a la mayoría de los programadores practicantes. También trató de no usar los términos "formal", "verificación" o "prueba", que recordaban a los programadores los tediosos ejercicios en el aula. En cambio, presentó TLA + como un nuevo tipo de "pseudocódigo", un trampolín hacia el código real que le permitió probar exhaustivamente sus algoritmos, y que lo hizo pensar con precisión al principio del proceso de diseño. "Los ingenieros piensan en términos de depuración en lugar de 'verificación'", escribió, por lo que tituló su charla interna sobre el tema a los ingenieros de Amazon "Diseños de depuración". En lugar de lamentarse por el hecho de que los programadores ven el mundo en código, Newcombe abrazó eso. Sabía que los perdería de otra manera. "He hecho que mucha gente diga:" Ahora lo entiendo "", dice Newcombe.

Desde entonces, dejó Amazon para ir a Oracle, donde pudo convencer a sus nuevos colegas para que probaran TLA+. Para él, usar estas herramientas es ahora una cuestión de responsabilidad. "Necesitamos mejorar en esto", dijo. "Soy autodidacta, he estado codificando desde que tenía nueve años, así que mi instinto era comenzar a codificar. Esa es mi forma de pensar: dibujar algo, intentar algo y evolucionar ”. En su opinión, esto es lo que muchos programadores de hoy todavía hacen. "Buscan en Google y buscan en Stack Overflow" (un sitio web popular donde los programadores responden las preguntas técnicas) "y obtienen fragmentos de código para resolver problemas que tienen en el código lo pegan y continúan". "Y eso está completamente bien hasta que te encuentras con un problema real".

En el verano de 2015, un par de investigadores de seguridad estadounidenses, Charlie Miller y Chris Valasek, convencidos de que los fabricantes de automóviles no se tomaban los errores en el software lo suficientemente en serio, demostraron que un Jeep Cherokee 2014 podría ser controlado remotamente por piratas informáticos. Aprovecharon el hecho de que el automóvil tenía una conexión al movil (de modo que, por ejemplo, puede encender el automóvil el iPhone) y estaba conectado a los sistemas centrales, como el que controla los limpiaparabrisas, dirección, aceleración y frenos (para que, por ejemplo, pueda ver las pautas en la pantalla del retrovisor que responden al girar el volante). Como prueba del ataque, que desarrollaron durante las noches y los fines de semana, piratearon el auto de Miller mientras un periodista lo conducía por la carretera y lo volvieron loco; el periodista, que sabía lo que se avecinaba, entró en pánico cuando se apagaron los motores, obligándolo a moverse lentamente por un tramo de carretera sin arcén.

Aunque en realidad no crearon uno, demostraron que era posible escribir un software inteligente, un "gusano del vehículo", que usaría la computadora a bordo de un Jeep Cherokee pirateado para buscar y piratear a otros; Si hubieran querido, podrían haber tenido acceso simultáneo a una flota nacional de automóviles y SUV vulnerables. (Hubo al menos cinco modelos de Fiat Chrysler afectados, incluido el Jeep Cherokee). Un día podrían haberles dicho a todos que, por ejemplo, giraran repentinamente a la izquierda o apagaran los motores a alta velocidad.

"Tenemos que pensar en el software de manera diferente", me dijo Valasek. Las compañías automotrices han ensamblado durante mucho tiempo su producto final a partir de piezas fabricadas por cientos de proveedores diferentes. Pero donde esas partes alguna vez fueron puramente mecánicas, ahora, casi siempre, vienen con millones de líneas de código. Y aunque parte de este código, para el control de crucero adaptativo, para el frenado automático y la asistencia en el carril, ha hecho que los automóviles sean más seguros ("Las características de seguridad en mi Jeep ya me han salvado innumerables veces", dice Miller), también ha creado un nivel de complejidad que es completamente nueva. Y ha hecho posible un nuevos tipos de fallos.

"Hay muchos errores en los automóviles", dijo Gerard Berry, el investigador francés detrás de Esterel, en una charla. "No es como la aviónica, en aviónica se toma muy en serio. Y se admite que el software es diferente de la mecánica ". La industria automotriz es quizás una de las que aún no se han dado cuenta de que realmente están en el negocio del software.

"No tenemos en la industria automotriz un regulador para la seguridad del software que sepa lo que está haciendo", dice Michael Barr, el experto en software que testificó en el caso de Toyota. NHTSA, dice, “solo tiene una experiencia limitada en software. Han llegado a esto a partir de una historia mecánica ". Las mismas presiones regulatorias que han hecho que el diseño basado en modelos y la generación de códigos sean atractivos para la industria de la aviación han tardado más en llegar a la fabricación de automóviles. Emmanuel Ledinot, de Dassault Aviation, especula que también podría haber razones económicas para la diferencia. Los fabricantes de automóviles simplemente no pueden darse el lujo de aumentar el precio de un componente por unos pocos centavos, ya que se multiplica por millones de veces; Por lo tanto, las computadoras integradas en los automóviles deben reducirse al mínimo, con poco espacio para ejecutar el código que no se ha ajustado a mano para que sea lo más delgado posible. "La introducción del desarrollo de software basado en modelos fue, creo, durante la última década, demasiado costosa para ellos".

Uno sospecha que los incentivos están cambiando. "Creo que el automóvil autónomo podría empujarlos", me dijo Ledinot, "ISO 26262 y el automóvil autónomo podría empujarlos lentamente a adoptar este tipo de enfoque en las partes críticas" (ISO 26262 es un estándar de seguridad para automóviles publicado en 2011. ) Barr dijo lo mismo: en el mundo del automóvil autónomo, el software no puede ser una cosa ideada a última hora de cualquier manera. No se puede construir como los sistemas de reserva de aerolíneas actuales o los sistemas 911 o los sistemas de negociación de acciones. El código se pondrá a cargo de cientos de millones de vidas en el camino y tiene que funcionar. Esa no es una tarea pequeña.

"La informática es fundamentalmente invisible", dijo Gerard Berry en su charla. “Cuando sus neumáticos están desinflados, los mira, están desinflados. Cuando el software no funciona, usted mira el software y no ve nada ".

"Entonces eso es un gran problema".