Ortogonalidad (o “Cada cosa en su lugar”)

Orthogonality means that features can be used in any combination, that the combinations all make sense, and that the meaning of a given feature is consistent, regardless of the other features with which it is combined. The name is meant to draw an explicit analogy to orthogonal vectors in linear algebra: none of the vectors in an orthogonal set depends on (or can be expressed in terms of) the others, and all are needed in order to describe the vector space as a whole.

Programming Language Pragmatics, Michael Scott, Morgan Kaufmann 2000

Ortogonalidad (en ingles Orthogonality) es una filosofía del diseño de sistemas que propone dividir de forma clara las distintas funcionalidades de estos, haciendo que estas funcionalidades no se pisen entre si y que compartan la mínima cantidad de código. El objetivo subyacente es el de evitar que cambios en alguna de las secciones de un programa repercuta en otra sección.

El nombre del concepto viene de la geometría, y en el desarrollo de software se adapta su significado para formar una metáfora que resalta la independencia, tanto en código como en utilidad, de dos componentes distintos de un mismo sistema.

Eric Lippert, diseñador de lenguajes en Microsoft (de los buenos, no de los otros) hizo un post en el 2005 sobre ortogonalidad titulado “Five-Dollar Words for Programmers, Part Two: Orthogonal”, en el definió el concepto de la siguiente manera:

Imagine for instance that you were trying to describe how to get from one point in an empty room to another. A perfectly valid way to do so would be to say how many steps to go north or south, and then how many steps to go northeast or southwest.  This hockey-stick navigation system is totally workable, but it feels weird because north and northeast are not orthogonal — you can’t change your position by moving northeast without also at the same time changing how far north you are.  With an orthogonal system — say, the traditional north-south/east-west system — you can specify how far north to go without worrying about taking the east-west movement into account at all.

Nonorthogonal systems are hard to manipulate because it’s hard to tweak isolated parts. Consider my fish tank for example. The pH, hardness, oxidation potential, dissolved oxygen content, salinity and conductivity of the water are very nonorthogonal; changing one tends to have an effect on the others, making it sometimes tricky to get the right balance. Even things like changing the light levels can change the bacteria and algae growth cycles causing chemical changes in the water.

Con este ejemplo Lippert deja en claro lo difícil que son de mantener los sistemas no-ortogonales donde la modificacion de un punto de un programa afecta a otras partes de este sin saberlo.

Otro ejemplo claro es el que da Dave Thomas con su analogía del helicóptero:

A helicopter has four main controls: foot pedals, collective pitch lever, cyclic, and throttle. The foot pedals control the tail rotor. With the foot pedals you can counteract the torque of the main blade and, basically, point the nose where you want the helicopter to go. The collective pitch lever, which you hold in your left hand, controls the pitch on the rotor blades. This lets you control the amount of lift the blades generate. The cyclic, which you hold in your right hand, can tip one section of the blade. Move the cyclic, and the helicopter moves in the corresponding direction. The throttle sits at the end of the pitch lever.

It sounds fairly simple. You can use the pedals to point the helicopter where you want it to go. You can use the collective to move up and down. Unfortunately, though, because of the aerodynamics and gyroscopic effects of the blades, all these controls are related. So one small change, such as lowering the collective, causes the helicopter to dip and turn to one side. You have to counteract every change you make with corresponding opposing forces on the other controls. However, by doing that, you introduce more changes to the original control. So you’re constantly dancing on all the controls to keep the helicopter stable.

That’s kind of similar to code. We’ve all worked on systems where you make one small change over here, and another problem pops out over there. So you go over there and fix it, but two more problems pop out somewhere else. You constantly push them back—like that Whack-a-Mole game—and you just never finish. If the system is not orthogonal, if the pieces interact with each other more than necessary, then you’ll always get that kind of distributed bug fixing.

The funny thing about the helicopter story is that I’m not a helicopter pilot. When I wrote the helicopter story, I wanted to make sure it was accurate. I knew of a USENET group on helicopters, so I posted the helicopter story saying, “This is what I’m intending to write about how helicopter controls work. Is it correct? A helicopter pilot emailed me and said, “I read what you wrote about controlling helicopters. I didn’t sleep all night.”

El ejemplo del helicóptero es un clásico al explicar ortogonalidad, de hecho Thomas vuelve a usar esta analogía en el libro The Pragmatic Programmer (Andrew Hunt y David Thomas, Addison-Wesley 1999), creo que la encuentra bastante efectiva para explicar la idea.

¿Alguna ves les paso tener un sistema donde un cambio en una función o clase tuvo efecto en otro extremo del programa, aun cuando no parecían estar relacionados en nada? Ese es un ejemplo de sistema-no ortogonal.

El logro de los sistemas ortogonales es que eliminan efectos entre elementos de nuestros programas que no están relacionados. La separación y buena encapsulacion facilitan mucho el poder programar sobre seguro, sabiendo que los cambios hechos solamente van a afectar las partes del programa que estamos modificando.

Otro beneficio de los sistemas ortogonales es que facilitan reutilizar el código. Si el código es realmente independiente del resto del sistema y no depende de otros elementos es muy simple la tarea de aislarlo en su propio modulo y reutilizarlo en otros programas.

También los sistemas ortogonales son fáciles de tededear (Lease diseñar/programar con Test Driven Development mas conocido como TDD y pronunciado tedede): Unit test y test funcionales pueden ser aplicados a secciones mucho mas limitadas (menos variables y condiciones extraordinarias), permitiendo que estos tests sean claros y mas confiables.

Yo tuve una experiencia muy grata participando del equipo que diseño y programo el reemplazo del sistema para edición y envío de noticias por SMS donde trabajo. Primero una pequeña descripción del sistema viejo:

Era monolítico. Se basaba en dos bases de datos, una que tenia los usuarios subscriptos al servicio, y otra que tenia los horarios de envío, las noticias a enviar, las noticias enviadas, y los distintos canales en los que se organizaban esas noticias. También los programas que cargaban datos en esas bases estaban viciados de no-ortogonalidad: Compartían funciones de formas no-directas (marcaban un campo en la base de datos, o un archivo en disco, o un registro en el registro de Windows). De mas esta decir que el sistema era inmantenible, estuvo funcionando mal durante varios años antes de que se planteara reemplazarlo. Y aun así cuando se lo hizo fue difícil hacer un relevamiento de que hacia exactamente para poder empezar a hacer un nuevo sistema.

Para el sistema nuevo nos pusimos como objetivo que sea ortogonal. En ese momento no conocíamos el concepto por su nombre, llamábamos al diseño “modular”, pero la definición de ese objetivo coincidía con la de ortogonal. Separamos las distintas funcionalidades del sistema en partes bien definidas, que de hecho eran programas separados y tenían su propia base de datos, código, y en algunos casos hasta lenguajes de programación distintos. El resultado final fueron varios sistemas: Uno mantiene los subscriptos a los servicios. Otro tiene un editor de contenidos web. Un tercero mantiene los horarios de envío. Y finalmente un “enviador” que consulta esas tres fuentes de datos y envía las noticias en el momento correcto a los usuarios que así lo desean.

No existe punto de comparación entre la complejidad de los dos sistemas. El viejo, no ortogonal, tenia muchas mas lineas de código y llevaba mas tiempo mantener a los programadores a cargo. Su diseño no-ortogonal hacia confuso cuando algo fallaba: No se sabia por donde empezar a buscar. El nuevo funciona en horario, es mucho mas claro que falla cuando hay algún error y requiere de muchas menos horas-hombre para mantenerlo ¡y extenderlo!. Aparte, como beneficio del diseño ortogonal, los nuevos sistemas se utilizan para otras tareas que la de envío de SMS; como la base de datos de subscriptores que ahora tiene usuarios de otros sistemas.

La ortogonalidad también tiene sus críticos, Ian Bicking en su articulo “Orthogonality is Pretentious” propone que el diseño de lenguajes de programación ortogonales puede resultar en varios problemas, como Ravioli Code donde terminan existiendo miles de pequeñas funciones no relacionadas entre si (¿Alguien dijo PHP?).

Finalmente esta ha sido llamada una de las “Five Dollar Programming words”, es decir uno de esos conceptos que al tener un nombre se vuelve mas fácil el ponerlos como un objetivo.