Cómo indentar el código para que sea limpio y legible

Como vimos en el artículo sobre cómo escribir código limpio y legible una de las características es la de que el código esté escrito con una buena indentación.

¿Qué es la indentación de un texto?

La palabra indentación, como otras muchas palabras tecnológicas, proviene de una traducción libre del término indentation. En castellano el término correcto sería espacio de sangrado para un texto.

En pocas palabras es el espacio vacío situado a la izquierda de una línea de texto.

En un bloque de texto con varias líneas podemos tener distintos niveles de sangrado. Cuando esto ocurre esa diferencia de espacios vacíos a la izquierda empieza a tener significado ya que visualmente nos permite identificar las diferencias entre una línea y la siguiente.

En el caso de algunos lenguajes de programación como Python o el lenguaje de formateado de datos YAML el nivel de indentación tiene un significado claro ya que se utiliza para indicar el comienzo de un bloque o dominio.

En otros lenguajes el nivel de indentación se utiliza para identificar fácilmente si una línea de código pertenece a un bloque condicional, una función o bloque de código. De esta forma podemos encontrar visualmente cuándo comienza y termina una función o un conjunto de instrucciones que pertenecen a un mismo bloque de código.

¿Espacio o tabulación?

Dentro del mundo de la programación hay personas que prefieren utilizar el caracter de espacio para indentar el código y otras personas prefieren el caracter de tabulación. Esto honestamente no tiene demasiada importancia siempre y cuando no mezclemos tabulaciones con espacios y seamos coherentes con nuestra forma de indentar el código.

Además los editores de código más habituales nos permiten seleccionar entre espacio o tabulación para indentar nuestro código.

Indentación y accesibilidad

La indentación del código puede resultar invisible a programadores ciegos que utilicen el lector de pantallas mediante una síntesis de voz. Utilizando una línea braille o braille display el nivel de indentación es visible gracias a que los caracteres en blanco son legibles a través del dispositivo de lectura braille.

Para facilitar la tarea de identificar el nivel de indentación de una línea para los usuarios de lectores de pantalla con voz se incluyen características en estos productos de apoyo para identificar el nivel de indentación de una línea de textos. Tanto JAWS, NVDA como ORCA incluyen opciones para activar la identificación del nivel de indentación de un texto. Incluso permiten activar un modo para que el lector de pantallas avise al usuario de que el nivel de indentación ha cambiado cuando sube o baja por el fichero de código.

En el caso de VoiceOver para MacOS esta opción no está disponible por defecto pero podemos utilizar un AppleScript para saber el nivel de indentación de un texto.

Cómo escribir código limpio y legible

Dentro del mundo de la programación un profesional se dedica a realizar muchas tareas pero la más habitual, además de pensar en solucionar problemas y resolverlos, es la de escribir código en un lenguaje de programación.

Este código puede estar escrito de muchas formas y un buen profesional deberá procurar que su código sea lo mas limpio y legible.

Las razones para este esfuerzo son las siguientes:

  • Un código limpio es más fácil de mantener ya que la lectura y el seguimiento de qué está haciendo el código mejora y la detección de errores es más sencilla.
  • Incorporar hábitos de escritura limpia va educando la mente del programador y mejora la detección de posibles errores mientras se escribe el código.
  • Colaborar y compartir con otros programadores es más sencillo ya que el código es más comprensible para todos.

Todas estas razones hacen que el escribir código limpio sea indispensable para un programador profesional que trabaja en un equipo de desarrollo.

Características de un código limpio

Estas son las características que debe cumplir un código para considerarse limpio.

  • Buena indentación del código
  • Nombres explícitos para variables, funciones y clases
  • Funciones cortas y sencillas
  • Sin código innecesario o comentado
  • Consistencia y legibilidad
  • Código con comentarios útiles

En futuros artículos veremos cada una de estas características en detalle.

Qué son los patrones de diseño en la industria del software

Los patrones de diseño son soluciones habituales a problemas que aparecen durante el diseño de un producto software.

Un patrón no es una pieza de código, sino un concepto general para resolver un problema concreto.  El patrón de diseño ayuda con ciertas instrucciones a implementar una solución que se adapte a las necesidades del programa que se esté creando..

Patrones y algoritmos

No se deben confundir los conceptos de algoritmo y patrón de diseño. El algoritmo es una receta para solucionar un problema muy concreto y el patrón de diseño es un plano arquitectónico para indicar cómo repartir las funciones, clases y objetos en nuestro programa.

Descripción de un patrón de diseño

La descripción de un patrón de diseño es un texto formal que permite la implementación del patrón en múltiples entornos y contextos.

Esta descripción del patrón incluye elementos como propósito, motivación, estructura de clases, aplicabilidad, pasos de implementación y ejemplo de código.

Clasificación

Los patrones de diseño se diferencian en su complejidad, nivel de detalle y escala de aplicabilidad.

Los patrones más básicos se denominan idioms y suelen aplicarse a un lenguaje de programación específico.

Los patrones más complejos y de alto nivel se denominan patrones de arquitectura y son aplicables a casi cualquier lenguaje de programación. Estos patrones ayudan al diseño global de la aplicación definiendo la arquitectura del proyecto software.

Clasificación por propósito

Los patrones de diseño se pueden clasificar también por el tipo de propósito que tenga el patrón de diseño.

Patrones de construcción

Estos patrones proporcionan mecanismos y enfoques para la creación de objetos buscando mejorar la reutilización de código y su flexibilidad.

Patrones de estructura

Estos patrones ofrecen soluciones para ensamblar y relacionar objetos para crear estructuras más grandes y maximizar su eficiencia y flexibilidad.

Patrones de comportamiento

Estos patrones ofrecen mecanismos para mejorar la comunicación entre objetos y definir las responsabilidades entre clases y objetos.

El polimorfismo dentro de la programación orientada a objetos

El polimorfismo permite que una clase hija modifique el comportamiento de un método de la superclase.

Ejemplo con la música

Queremos realizar una aplicación que haga sonar varios instrumentos musicales a la vez para interpretar una composición musical.

Como podemos modelar nuestra orquesta de la forma que prefiramos podemos crear una clase DirectorDeOrquesta que dará órdenes a un listado de instrumentos musicales. De esta forma nuestro director de orquesta puede dar órdenes a una orquesta que tenga un tamaño indeterminado.

Para conseguir esto cada instrumento musical debe responder a una órden específica del director de orquesta. Esta órden puede estar representada por una llamada al método tocar de cada instrumento musical.

Nuestra clase directorDeOrquesta sería algo como:

Clase Director

    atributos: listaDeInstrumentos

    Métodos: tocarLista

Imaginemos que tenemos la clase InstrumentoMusical y la declaramos así:

Clase InstrumentoMusical

    Atributos: nombre, tipo

    Métodos: tocar

Esta clase al ejecutar el método tocar mostrará un mensaje por pantalla.

Veamos la definición de la clase InstrumentoMusical con más detalle:

Clase InstrumentoMusical

    nombre, tipo



    función tocar() {

        imprime("El instrumento suena")

    }

Ahora imaginemos que queremos declarar las clases Flauta y la clase tambor. La declaración quedaría así:

Clase Flauta que hereda de InstrumentoMusical

    función tocar() {

        imprime("Piiiiiiii")

    }



Clase Tambor que hereda de InstrumentoMusical

    función tocar() {

        imprime("Bum")

    }

De esta forma las clases hijas tienen comportamientos personalizados para el método tocar que ha sido heredado de su clase padre.

El polimorfismo es la capacidad de un programa de detectar la verdadera clase de un objeto e invocar su implementación, incluso aunque su tipo real sea desconocido en el contexto actual.
También se puede pensar en el polimorfismo como la capacidad de un objeto para “fingir” ser otro objeto,

La herencia dentro de la programación orientada a objetos

La herencia es la capacidad de crear nuevas clases a partir de otras clases anteriores.

La principal ventaja de la herencia es la reutilización de código.

Si se quiere crear una clase ligeramente diferente a una ya existente, no es necesario duplicar el código. En su lugar, se amplía la clase existente y se coloca la funcionalidad adicional dentro de una subclase resultante que hereda los campos y métodos de la superclase.
Una de las consecuencias del uso de la herencia es que las subclases tienen la misma interfaz que su clase padre. No se puede esconder un método en una subclase si este mismo método se declaró en la superclase de forma pública.

Las interfaces de clase dentro de la programación orientada a objetos

Ahora que conocemos los conceptos de abstracción y encapsulación podemos hablar de las interfaces de clase dentro de la programación orientada a objetos.

La interfaz de una clase es un listado de métodos que, en el caso de tratarse de una interfaz pública, estos métodos son conocidos por los objetos alrededor de nuestra clase.

Las interfaces y la forma de modelar las clases y métodos abstractos en la mayoría de los lenguajes de programación se basan en conceptos de abstracción y encapsulación.

En los lenguajes modernos de programación orientada a objetos, el mecanismo de la interfaz (declarado normalmente con la palabra clave interface o protocol) permite definir contratos de interacción entre objetos. Esto recalca el interés de reflejar en las interfaces sólo los métodos y no los atributos por esta razón hay muchos lenguajes de programación orientada a objetos que no permiten la declaración de atributos en las interfaces de clase.

Una clase puede tener una interfaz pública, otra interfaz privada y otra interfaz protegida dependiendo de cómo se declaren los distintos métodos de la clase. De esta forma los métodos de la clase estarán disponibles a distintos niveles de complejidad.