Evolución del software

De Jose Castillo Aliaga
Revisión del 09:10 23 ago 2012 de Admin (discusión | contribs.)
(difs.) ← Revisión anterior | Revisión actual (difs.) | Revisión siguiente → (difs.)
Ir a la navegación Ir a la búsqueda

La forma más sencilla de controlar una máquina electrónica es con señales eléctricas. La dos señales obvias son el encendido y el apagado. Por tanto, el alfabeto de la máquina sólo tiene dos letras y con esas debe crear todo un lenguaje. Estas dos letras se pueden representar como el 0 y el 1, los números binarios.

Inicios

Los primeros programadores se comunicaban con las máquina sólo con 0's y 1's. Era lo que llamaban el lenguaje máquina. Sin embargo, esto era muy tedioso, por lo que el primer paso para simplificar esta comunicación fue inventar notaciones simbólicas que tradujeran una secuencia de 0 y 1 que representa una instrucción en una palabra. Así, para escribir los programas usaban el lenguaje ensamblador.

add A,B → 1000110010100000

El lenguaje ensamblador tiene las mismas instrucciones que el procesador donde se va a ejecutar. Si bien con el ensamblador ya no se necesita conocer todos los códigos de las instrucciones, este presenta algunas desventajas:

  • No es portable, es decir, no se puede ejecutar un mismo código en dos procesadores distintos.
  • Las instrucciones son de muy bajo nivel. Eso quiere decir que cualquier programa requiere muchas instrucciones.
  • Es complicado de leer y de seguir su secuencia.
  • No permiten crear funciones o reutilizar código de manera sencilla. Con excepción de las macro.

En teoría, con el lenguaje ensamblador se pueden crear los programas más óptimos. Por lo que actualmente se usa sólo en esos casos y en los microcontroladores que no tienen un lenguaje de alto nivel para ser programados.

Compiladores

La poca facilidad para programar en ensamblador y la dificultad para hacer los programas portables hizo que se crearan los lenguajes de alto nivel.

Lenguajes como C, creado para desarrollar Unix, permiten programar con palabras y símbolos más cercanos al lenguaje humano. Más tarde, el compilador se encarga de traducirlo al lenguaje máquina.

Cuando se ejecuta un compilador, este tiene dos fases: la de análisis y la de síntesis:

La fase de análisis comprueba la corrección del código del programa fuente.

Para ello realiza en primer lugar un análisis léxico. Un lenguaje de programación es una representación formal de los algoritmos o funciones del sistema. Por ello tiene una serie de símbolos que pertenecen al lenguaje. El análisis léxico comprueba que todos los símbolos que hay en el código fuente pertenezcan al lenguaje de programación. El análisis léxico, si a nivel de símbolos está correctamente escrito en código fuente, crea una tabla de símbolos, que servirá para el siguiente análisis.

El siguiente análisis es el sintáctico. Este componente del compilador también se llama parser. Realiza su análisis a nivel de sentencia Es mucho más complejo, ya que debe coger los tokens que ha dejado en la tabla de símbolos el analizador léxico y determinar la estructura de cada una de las expresiones del código fuente.

El analizador semántico detecta la validez en cuanto al significado de las expresiones que ha aceptado el análisis semántico. Estas son sus funciones:

  • Detectar si las variables, constantes y funciones han sido declaradas antes de ser utilizadas.
  • Verificar que las variables, constantes y funciones sean accesibles (visibilidad) desde el ámbito en que son utilizadas.
  • Comprobar que los diferentes identificadores solo hayan sido declarados una vez.
  • Comprobaciones de tipos al evaluar las expresiones. Por ejemplo que no se multiplique un número por una cadena o que la expresión a evaluar en un IF sea del tipo booleano.
  • Verificar que no se intente modificar el valor de una constante.
  • Generar la tabla de símbolos.

La fase se síntesis traduce del código fuente al código objeto. En primer lugar realiza una traducción del código fuente al código intermedio. Este no corresponde a ninguna máquina real, sino a una máquina abstracta que define el comportamiento de manera general de cualquier máquina. El objetivo del código intermedio es reducir el número de programas necesarios para construir compiladores.

De esta manera, un compilador tiene un frontend que traduce a código intermedio y un backend que lo traduce a la máquina concreta que lo use. Cada lenguaje de programación tiene su frontend que lo traduce a un mismo lenguaje intermedio. Cada máquina tendrá su backend que coge el lenguaje intermedio y lo traduce a código objeto. Este código luego es enlazado por unos programas llamados Linkers y entonces puede ya ser ejecutado.

La siguiente parte de la fase de síntesis es la optimización del código intermedio. En este punto aprovecha propiedades algebraicas de los operadores, reduce expresiones comunes o elimina bucles innecesarios. A continuación pasa a la generación de código. El código intermedio se pasa a código máquina. Entonces aun se puede optimizar más al aprovechar características propias de la máquina.

Hay varios tipos de compiladores. Los más simples son los de una pasada, los cuales ejecutan una sola vez la fase de análisis y síntesis para retornar el programa. Otros tienen múltiples pasadas ya que necesitan leer el código fuente varias veces e ir generando un código intermedio. Otros son optimizadores, que cambian el código resultante sin afectar al funcionamiento del programa, pero mejorando el rendimiento. Otros compiladores son los cruzados, que permiten general código máquina diferente de la máquina en la que están.

Entre los lenguajes que usan compilador, los más usados son: C. C++, ADA, BASIC, PASCAL, FOLTRAN, COBOL, DELPHY o Visual BASIC.


Intérpretes

Algunos lenguajes de alto nivel no necesitan ser compilados, sino que un intérprete los analiza y ejecuta simultáneamente. El resultado de este interpretación no se guarda como un programa ejecutable.

Los programas interpretados suelen ser más lentos que los compilados debido a la necesidad de traducir el programa mientras se ejecuta, pero a cambio son más flexibles como entornos de programación y depuración (lo que se traduce, por ejemplo, en una mayor facilidad para reemplazar partes enteras del programa o añadir módulos completamente nuevos), y permiten ofrecer al programa interpretado un entorno no dependiente de la máquina donde se ejecuta el intérprete, sino del propio intérprete (lo que se conoce comúnmente como máquina virtual).

Para evitar el problema de la lentitud, sin perder la gran ventaja de poder hacer código multiplataforma, la mayoría de los lenguajes interpretados actuales se denominan híbridos. Dentro de estos hay una gran variedad de intérpretes dependiendo de la cantidad de código que se precompila y el que se interpreta. Dentro de esta variedad se pueden distinguir dos tipos de intérpretes híbridos:

Bytecode: Es un código intermedio más abstracto que el código máquina. Este código está optimizado y comprimido. El intérprete, generalmente llamado máquina virtual lo ejecuta más rápidamente, pero sigue siendo multiplataforma. Los lenguajes más comunes que usan bytecode son: PHP, Perl o Python.

Compiladores Just- In – Time. O JIT, Estos compilan el bytecode a código máquina en el momento de la ejecución. Java es el más representativo. El programador crea un código fuente que transforma a bytecode. Al ejecutarse por primera vez, este es compilado a código máquina por la máquina virtual. Luego se almacena ya compilado. Sigue siendo multiplataforma porque la máquina virtual se debe instalar en el ordenador cliente y ella lo adapta a la plataforma deseada.

Aunque el proceso de compilación o de transformación a bytecode no de errores, es posible que el programa resultante sí los de. Para facilitar la tarea a los desarrolladores, hay unos programas que permiten encontrar el error más fácilmente:

Depuradores

Hay multitud de situaciones en las que un error no se detecta en el momento de la compilación. Puede haber una división por cero o intentar acceder a una posición de memoria no permitida. Los depuradores ejecutan el programa que da el error y permiten detener el programa en algún punto de ruptura ya definido y en ese momento, el programador puede observar la situación de la memoria o las variables. También puede ejecutar una a una las instrucciones o las funciones, puede insertar código o hacer que salte alguna instrucción. De esta manera, podrá detectar la razón del error. Al compilar, es necesario indicar que el código resultante debe tener las indicaciones necesarias para el depurador. Los depuradores se pueden usar para técnicas de ingeniería inversa cuando se necesite conocer las instrucciones de un programa.

Herramientas RAD

El RAD o desarrollo rápido de aplicaciones, consiste en un conjunto de técnicas para agilizar el desarrollo de software. Este incluye el desarrollo iterativo con construccion de prototipos y el uso de herramientas CASE e IDEs.

Las herramientas CASE o Ingeniería de Software Asistida por Ordenador son diversas aplicaciones informáticas destinadas a aumentar la productividad en el desarrollo de software reduciendo el coste de las mismas en términos de tiempo y de dinero. Estas herramientas pueden ayudar en todos los aspectos del ciclo de vida de desarrollo del software. Estas son muy variadas y no es posible dar una definición de todas ellas. Pero por su funcionalidad se pueden clasificar en: Herramientas de generación semiautomática de código Editores UML Herramientas de refactorización del código Herramientas de control de versiones. Algunas aplicaciones comerciales cubren más de una de estas funciones.

La manera en que el usuario final se comunica con las funciones de la aplicación puede ser mediante interfaces alfanuméricas o de forma gráfica. Actualmente, casi todas las aplicaciones se desarrollan pensando en una interfaz gráfica. El diseño de estas aplicaciones, por tanto, se realiza casi al mismo tiempo que el de sus funcionalidades. A la hora de diseñar una interfaz, hay que tener en cuenta una serie de criterios estéticos y de accesibilidad y usabilidad. Las aplicaciones para desarrollar software con interfaz gráfica son los IDE o Entornos de Desarrollo integrado. Algunos incluyen funciones de las herramientas CASE. Pero su característica principal es que permiten editar el código, compilarlo, depurarlo y diseñar la interfaz gráfica. La diferencia entre una herramienta CASE y un IDE actualmente está muy diluida. En el diseño de la interfaz grafica está su verdadera potencia, ya que permite dibujarla como si fuera un programa de diseño y luego añadir funcionalidad a los elementos introducidos en la interfaz. De esta manera, un prototipo horizontal se elabora rápidamente y el programador sólo se preocupa de las funciones de la aplicación.

Herramientas como Visual Basic, Delphi, o Netbeans son IDEs de los lenguajes Basic, Pascal y Java respectivamente. Algunas añaden funciones o instrucciones propias a estos lenguajes. Para la interfaz gráfica, algunos sistemas operativos ofrecen unas primitivas gráficas como botones, ventanas o barras de desplazamiento. Los IDEs pueden hacer uso de ellas, aunque algunos las extienden y otros tienen las suyas propias como las librerías SWING de java.