No es fácil elegir un lenguaje de programación para cada proyecto. Dependiendo de las características del proyecto, entorno, etc.. deberemos de elegir bien. Será más complejo aún, si además convivirán varios sistemas informáticos interconectados, comunicándose entre sí. De la misma forma, será más complejo si en el proyecto tenemos elementos programados a bajo y alto nivel. También se añade complejidad si los entornos de ejecución son varios: escritorio, web, móvil.. o varios sistemas operativos.
Es importante tener claras las características, y conocer, por lo menos en líneas generales, la mayor cantidad de lenguajes. Así elegiremos bien, y luego profundizaremos más y más a lo largo del proyecto, o subproyecto. Una mala decisión inicial del lenguaje, framework o plataforma, acarreará grandes problemas a la larga. Puede desembocar en grandes gastos y esfuerzos que se podrían haber evitado, o en una merma de la calidad final del proyecto.
Un lenguaje de programación no puede convertirse en una religión. Debemos de salir de nuestra área de confort, ir cambiando y probando diferentes lenguajes. Si nos queremos mantener en buena forma mental, como programadores, deberemos aprender contínuamente. No podemos estancarnos en un sólo lenguaje. Debemos de hacer practicar a nuestro cerebro como si de hacer deporte se tratara, combinando de manera políglota los diferentes lenguajes..
Las características
Estas características se conocen, o se establecen como prioridades a la hora de diseñar un lenguaje, de construir el compilador que traduce o interpreta el código fuente. No son características sólo desde el punto de vista del día a día del que pica el código, o del que paga el proyecto.
Eficiencia
La eficiencia de un lenguaje, también conocida como optimizabilidad, es la facilidad con la que se genera el código ejecutable eficientemente. De aquí se deriva en varias subcategorías de eficiencia:
- De la implementación: es la facilidad con la que se puede implementar el traductor. No la eficiencia con la que traduzca, sino la eficiencia con la que se implementa el traductor.
- De la traducción: es la facilidad con el se puede construir un traductor que traduzca eficientemente y de poco tamaño. Aquí entran aspectos como la cantidad de pasadas que debe hacer el traductor al código fuente. Lo flexible que permite el lenguaje al programador hacer el código, se convierte en complejidad en el desarrollo del traductor. Hay flexibilidades que provocan poca fiabilidad a la hora de ejecutar los programas, porque pueden haber errores con ciertas ejecuciones. Por ejemplo: permitir variables que cambien de tipo complica la vida al traductor y la facilita al programador, pero tener que definir todas las variables al principio de un bloque facilita las cosas al traductor y la complica al programador final.
- De la programación: es la referente a la hora de programar, con que facilidad los programadores construimos los programas. Aquí entran conceptos como la el azúcar sintáctico, que se refiere a las estructuras sintácticas que no añaden nada nuevo, pero facilitan diferentes maneras de programar lo mismo (por ejemplo las diferentes formas de bucles).
Regularidad
La regularidad de un lenguaje se estudia viendo cómo se comportan las características de un lenguaje, si están bien integradas. Se subdivide en generalidad, otogonalidad y uniformidad. Si alguna no se cumple se marcará como lenguaje irregular.
- Generalidad: un lenguaje tiene generalidad eliminando casos especiales de los constructores. Por ejemplo, deben tener variables de procedimientos, anidación de funciones, arreglos de longitud variable, creación de nuevos operadores.
- Ortogonalidad: los constructores se deben comportar de igual forma en todos los contextos, además, se deben de poder combinar de cualquier forma significativa y que no incurra en comportamientos inesperados. Esto desemboca en facilidad de programación, pero dificultad el hacer el traductor, y quizá puede desembocar en ejecuciones ineficientes ya que provee de mucha flexibilidad al programador.
- Uniformidad: se refiere a que lo parecido se ve parecido y lo distinto distinto. Por ejemplo, si toda sentencia debe acabar con un punto, entonces absolutamente todas las sentencias deben acabar con un punto para ser uniforme.
Simplicidad
Se refiere a la cantidad de estructuras o conceptos que están disponibles en un lenguaje para construir los programas. Si hay pocos constructores es simple. Por ejemplo, BASIC es un lenguaje simple porque tiene pocos constructores, pero esto dificulta la construcción de aplicaciones complejas y grandes.
Es decir, un lenguaje es simple si tiene la menor cantidad de constructores. Hay que tratar la simplicidad de un lenguaje desde el punto de vista semántico (cantidad de conceptos) y sintáctico (código fácil de leer por lo simple de su sintaxis).
Expresividad
Es la cualidad de un lenguaje de programación que permite representar procesos y estructuras complejos. Es esta característica encontramos por ejemplo la recursividad, lenguajes orientados a objetos, datos de tamaño variable.
Este concepto puede entrar en conflicto con la simplicidad sintáctica, teniendo código menos legible.
Extensibilidad
Es la capacidad de poder añadir nuevas características al lenguaje, como librerías, sobrecarga de operadores, nuevos operadores o modularidad. Esta modularidad desenboca en la escalabilidad de los proyectos, con los que la ampliación y/o reutilización de códigos fuentes se facilite.
Capacidad de restricción
Característica que tienen los lenguajes para que un programador no tenga que conocer muchos contructores para resolver el problema que está desarrollando. Es decir, un lenguaje tiene capacidad de restricción si un programador puede centrarse en un subconjunto mínimo de conceptos del lenguaje para ser posible que construya la solución que necesita.
Esto facilita el desarrollo incremental de los lenguajes, así se van añadiendo nuevas funcionalidades sin que sea necesario utilizarlas. Con esto entra en juego la eficiencia del lenguaje, porque no usar ciertas funcionalidades, aunque estén disponibles, no debe resultar el programas que se ejecuten más lentamente.
Uso de las convenciones y notaciones estandarizadas
Los lenguajes deben utilizar las notaciones y convenciones estandarizadas. Por ejemplo el uso de operadores aritméticos básicos, estructuras de control if-else while for.. Este uso repercute directamente en hacer más fácil la migración desde otros lenguajes, ocurren menos errores, es más eficiente en la programación.
Precisión
Los lenguajes deben ser precisos en su interpretación, es decir, se deben comportar siempre tal y como se espera que se comporten. Esta precisión repercute en que sean predecibles, y a su vez, influye en la portabilidad, ya que facilita la creación de traductores.
Portabilidad
Es la posibilidad de contruir programas independientes de la máquina donde se ejecuten. Es muy interesante en este punto notar que los lenguajes que se ejecutan sobre máquinas virtuales son totalmente portables: Java, Scala, PHP..
Seguridad
Se refiere a la predicción de errores en el código fuente, evitándolos. Para hacer más seguros los lenguajes de programación se compromete en cierta medida la expresividad de estos. El tipado de variables debe ser estricto, y su verificación.
Interoperabilidad
Referido a la propiedad que tienen los programas de interactuar entre sí. Deben proveer de mecanismos de intercomunicación entre sí, de forma que no haga falta una comunicación previa para intercambiar información.
De esto se derivan estándares del W3C, lenguajes de marcado como el XML, la estandarización de las API Rest.
También se puede dar interoperabilidad a nivel de lenguaje dentro de un programa. En este caso podemos encontrar cómo usamos SQL dentro de otros programas. También encontramos cómo Scala se compila a bitecode compatible con la Máquina Virtual de Java, pudiendo usar cualquier librería programada en Java. A menudo hay soluciones en las que se combinan varios lenguajes de programación en un mismo programa.