Barbara Liskov ha dedicado su carrera a una dificultad que acompaña a
todo gran sistema de software: ¿cómo modificar una parte sin tener que
comprender ni reescribir todas las demás? Su respuesta se basa en
interfaces precisas, representaciones ocultas y propiedades que los
componentes deben seguir respetando a medida que evolucionan.
Este enfoque produjo varias contribuciones duraderas. En la década de
1970, Liskov y su equipo del MIT diseñaron CLU, el primer lenguaje
implementado que incorporó directamente la abstracción de datos. Sus
trabajos sobre jerarquías de tipos condujeron después al principio de
sustitución que lleva su nombre. Argus, Viewstamped Replication y sus
investigaciones sobre tolerancia a fallos aplicaron la misma exigencia
de razonamiento a programas distribuidos entre varias máquinas.
Liskov no se limitó a añadir funciones a los lenguajes. Ayudó a definir
un método: describir qué garantiza un componente, ocultar cómo lo
consigue y preservar ese contrato cuando el sistema crece.
Del cálculo científico al problema de la complejidad del software
Barbara Huberman nació en Los Ángeles en 1939 y creció en San Francisco.
Estudió matemáticas en la Universidad de California en Berkeley y en
1961 se incorporó a MITRE Corporation como programadora. La informática
universitaria aún era joven y la formación especializada escasa, por lo
que aprendió materias como Fortran en el trabajo.
Después cursó estudios de posgrado en informática en Stanford bajo la
dirección de John McCarthy. Su tesis, terminada en 1968, trataba sobre
un programa de ajedrez. Liskov se convirtió en una de las primeras
mujeres de Estados Unidos en obtener un doctorado expedido por un
departamento de informática, en un campo donde las mujeres seguían
siendo una pequeña minoría.
De regreso a MITRE, participó en el sistema experimental Venus. Este
trabajo la condujo a un problema más general que escribir un algoritmo
aislado. El hardware posee fronteras visibles: los componentes se
conectan mediante interfaces definidas. En el software, por el
contrario, nada impide de forma inherente que una parte acceda a los
detalles de otra. Cuando el programa crece, estas dependencias vuelven
arriesgado cada cambio.
Al incorporarse al MIT a comienzos de los años setenta, Liskov buscó
restricciones intelectuales y lingüísticas capaces de dar al software
una modularidad comparable.
La abstracción de datos: separar el contrato de la representación
Un tipo abstracto se define por las operaciones que ofrece y por las
propiedades que estas garantizan, no por la estructura de datos empleada
internamente. Una pila, por ejemplo, puede exponer apilar, desapilar
y cima. El código cliente debe razonar sobre su comportamiento sin
saber si la pila utiliza un array, una lista enlazada u otra
representación.
Esta separación aporta tres beneficios relacionados:
- el cliente trabaja con una interfaz menor que la implementación
completa;
- el autor del módulo puede cambiar la representación sin perjudicar a
sus usuarios;
- las propiedades del módulo pueden explicarse y comprobarse de forma
independiente al resto del sistema.
La novedad no consistía simplemente en agrupar subrutinas. Liskov situó
en el centro la barrera de abstracción: los valores del tipo solo
pueden crearse y observarse mediante las operaciones autorizadas. La
implementación queda realmente oculta, en lugar de depender de una
convención que cualquier llamada puede eludir.
Este razonamiento resulta familiar porque hoy estructura clases,
módulos, bibliotecas y API. A comienzos de los setenta todavía era
necesario demostrar cómo podía imponerlo un lenguaje y cómo construir un
sistema completo a partir de estas unidades.
CLU: incorporar la abstracción al lenguaje
A partir de 1973, el Programming Methodology Group del MIT convirtió
esta idea en un lenguaje experimental: CLU, cuyo nombre procede de
cluster. Un cluster reúne la representación privada de un tipo y las
operaciones públicas que permiten manipularlo.
Liskov dirigió el proyecto, pero CLU fue una creación colectiva. Alan
Snyder, Russell Atkinson, Craig Schaffert y otros estudiantes e
investigadores participaron en el diseño, el compilador, el entorno y la
documentación. El proyecto permitió probar las ideas en programas reales
en vez de publicar únicamente una notación teórica.
CLU introdujo o combinó varios mecanismos que influirían en lenguajes
posteriores:
- tipos abstractos con representación oculta;
- tipos parametrizados, que permiten definir una colección
independientemente del tipo de sus elementos;
- iteradores que recorren una estructura sin revelar su organización
interna;
- gestión estructurada de excepciones;
- memoria gestionada automáticamente y objetos accesibles por
referencia.
El lenguaje no se convirtió en un gran producto industrial. En los años
setenta, difundir un lenguaje universitario exigía adaptaciones, soporte
duradero y, a menudo, la adopción de una empresa. Según Liskov, unos
cientos de grupos lo utilizaron, pero su equipo acabó centrándose en
nuevos temas de investigación.
Su influencia fue, aun así, profunda. Mecanismos hoy habituales en Ada,
C++, Java, C#
y otros lenguajes modernos abordan, con sintaxis y modelos distintos,
problemas que CLU había colocado en el centro de su diseño.
Del tipo abstracto al principio de sustitución
Ocultar una representación no basta cuando los tipos se organizan en una
jerarquía. Si un programa espera un objeto de un tipo y recibe uno de un
subtipo, ¿es siempre segura esa sustitución? Una simple semejanza entre
métodos no garantiza comportamientos compatibles.
En 1987, Liskov formuló una propiedad de subtipado conductual que
después desarrolló con Jeannette Wing. En términos prácticos, el
principio de sustitución de Liskov afirma que un objeto de un
subtipo debe poder reemplazar a uno del tipo base sin volver falso
aquello que el programa cliente podía suponer legítimamente.
Pensemos en un tipo Cuenta cuya operación de retirada garantiza que
una cantidad aceptada se descontará del saldo. Un subtipo que rechaza
arbitrariamente retiradas permitidas por ese contrato no constituye un
reemplazo correcto, aunque tenga un método con el mismo nombre. Refuerza
una condición de llamada con la que el cliente no contaba.
El principio no se limita, por tanto, a exigir que «las subclases tengan
la misma interfaz». Deben preservar el significado de esa interfaz: no
exigir más a quien llama, no prometer menos como resultado y mantener
los invariantes anunciados.
Esta idea revela una limitación frecuente de la programación orientada
a objetos. Heredar código
puede resultar cómodo, pero una jerarquía solo es robusta si representa
una relación conductual coherente. Cuando el contrato no se cumple, la
composición o dos abstracciones separadas suelen ser preferibles.
Argus: mantener las abstracciones a pesar de los fallos
Después de CLU, Liskov aplicó sus métodos a los sistemas distribuidos.
En un programa ejecutado en varias máquinas, un fallo o un corte de red
puede interrumpir una operación. Algunas partes pueden continuar
mientras otras quedan inaccesibles. El programador debe conservar los
datos y evitar resultados aplicados de forma parcial.
El lenguaje Argus, desarrollado en el MIT desde finales de los años
setenta, organizaba el sistema alrededor de guardians. Cada guardian
encapsulaba un estado y las operaciones que accedían a él, prolongando
la lógica de los tipos abstractos en un entorno distribuido. Las
acciones atómicas agrupaban varios cambios: todos debían completarse o
anularse para no dejar el sistema en un estado incoherente.
Argus no eliminó la dificultad de los fallos. Ofreció abstracciones para
expresar dónde reside el estado, qué operaciones están protegidas y cómo
se recupera un cálculo. Este enfoque anticipó los marcos modernos donde
transacciones, servicios y replicación deben cooperar sin exponer cada
detalle de la red al código de aplicación.
Replicación, bases de objetos y tolerancia a fallos
Las investigaciones de Liskov trascendieron después los lenguajes. Junto
con Brian Oki, publicó en 1988 Viewstamped Replication, un protocolo
que mantiene varias copias coherentes de un servicio. Una réplica
principal ordena las operaciones; si falla, las demás deben seleccionar
una nueva vista y continuar sin perder las decisiones ya confirmadas.
El protocolo pertenece a la familia de técnicas de replicación de
máquinas de estados que hoy sustentan servicios distribuidos de alta
disponibilidad. Su importancia reside en la precisión con la que
relaciona el orden de las operaciones, el cambio de responsable y la
recuperación tras un fallo.
El proyecto Thor exploró después una base de datos orientada a objetos
que proporcionaba acceso transaccional a objetos persistentes. Más
tarde, Liskov y Miguel Castro trabajaron en la tolerancia a fallos
bizantinos, donde algunos nodos pueden comportarse de forma arbitraria
en vez de limitarse a detenerse.
Estos temas pueden parecer alejados de CLU, pero prolongan la misma
pregunta. Un componente debe ofrecer una garantía comprensible incluso
cuando su implementación es compleja, distribuida y susceptible de
fallar.
Una contribución colectiva convertida en infraestructura intelectual
Liskov recibió el Premio Turing de 2008 por sus contribuciones a los
fundamentos prácticos y teóricos de los lenguajes y el diseño de
sistemas. Este reconocimiento no convierte sus proyectos en obras
solitarias. CLU dependió del Programming Methodology Group; el principio
de sustitución se profundizó con Jeannette Wing; Viewstamped Replication
se diseñó con Brian Oki; y Argus, Thor y los sistemas tolerantes a
fallos movilizaron a numerosos estudiantes y colaboradores.
Su papel distintivo consistió en mantener un hilo conductor entre estos
trabajos. Partía de un problema concreto de construcción de software,
formulaba la abstracción necesaria, la incorporaba a un lenguaje o
sistema y después la evaluaba mediante una implementación.
Este método explica por qué CLU sigue siendo importante pese a su
limitada difusión. Un lenguaje de investigación puede transformar la
informática sin convertirse en dominante: hace que las ideas puedan
probarse, revela sus límites y proporciona un vocabulario que otros
ecosistemas pueden adoptar.
Por qué Barbara Liskov sigue siendo importante
Gran parte del desarrollo moderno se apoya en fronteras: API públicas,
módulos, servicios, tipos, contratos y protocolos. Estas fronteras
permiten que varios equipos trabajen por separado y que una
implementación evolucione sin imponer una reescritura general.
Los trabajos de Liskov recuerdan, sin embargo, que una frontera
sintáctica no basta. Un módulo útil debe ocultar los detalles adecuados.
Un subtipo debe preservar el comportamiento prometido. Un servicio
replicado debe mantener sus garantías cuando desaparece una máquina. La
abstracción no sirve para ignorar la realidad, sino para contenerla
detrás de un contrato explícito.
Esta exigencia conecta los lenguajes de programación con los sistemas
distribuidos. Tanto si se trata de una colección en memoria como de un
servicio repartido entre varios centros de datos, la pregunta permanece:
¿en qué propiedades puede confiar el resto del programa?
Cronología
- 1939: Barbara Huberman nace en Los Ángeles, California.
- 1961: se gradúa en matemáticas en la Universidad de California
en Berkeley y empieza a trabajar como programadora en MITRE.
- 1968: obtiene el doctorado en informática en Stanford bajo la
dirección de John McCarthy.
- 1972: se incorpora al MIT, donde desarrolla sus trabajos sobre
metodología de programación.
- 1973: comienza el proyecto CLU con el Programming Methodology
Group.
- 1976: se publica una presentación destacada de los mecanismos de
abstracción de CLU.
- Década de 1980: se desarrolla Argus para la programación
distribuida y las acciones atómicas.
- 1987: Liskov formula la propiedad de subtipado conductual que se
conocerá como principio de sustitución de Liskov.
- 1988: publica Viewstamped Replication con Brian Oki.
- 1994: publica con Jeannette Wing una formulación ampliada del
subtipado conductual.
- 2008: recibe el Premio Turing por sus contribuciones a los
lenguajes y el diseño de sistemas.
- 2018: recibe el IEEE Computer Pioneer Award por sus trabajos
sobre abstracción, CLU y Argus.
Preguntas frecuentes
¿Qué inventó Barbara Liskov?
Desempeñó un papel central en la formulación de la abstracción de datos,
dirigió la creación de CLU y formuló la propiedad que se convirtió en el
principio de sustitución de Liskov. También contribuyó a Argus,
Viewstamped Replication y varios sistemas de almacenamiento distribuido.
Cada uno de estos proyectos fue el resultado de un trabajo colectivo que
dirigió o realizó con colaboradores.
¿Qué es un tipo abstracto de datos?
Es un tipo definido por las operaciones y propiedades que garantiza,
mientras su representación interna permanece oculta. El código cliente
puede así utilizar una pila, un conjunto o una tabla sin depender de la
estructura concreta elegida para implementarlos.
¿Por qué es importante CLU si tuvo poco uso?
CLU permitió probar en un lenguaje completo los tipos abstractos, los
iteradores, las excepciones y los tipos parametrizados. Estos mecanismos
influyeron en el diseño y las prácticas de lenguajes posteriores, aunque
CLU no alcanzara una amplia difusión comercial.
¿Qué dice exactamente el principio de sustitución de Liskov?
Exige que un objeto de un subtipo pueda reemplazar a uno del tipo base
sin violar las propiedades en las que se apoya el programa cliente. La
compatibilidad se refiere, por tanto, al comportamiento prometido, no
solo a los nombres y las firmas de los métodos.
¿Qué relación existe entre CLU y los sistemas distribuidos de Liskov?
Ambos buscan contener la complejidad detrás de abstracciones explícitas.
CLU protege la representación de un tipo; Argus y los protocolos de
replicación protegen las garantías de un servicio pese a la
concurrencia, la distribución y los fallos.