La creació d'aplicacions complexes amb JavaScript comporta l'ús d'una metodologia específica. Si intentem abastar un problema complex sense seguir uns mètodes apropiats ens podem trobar desbordats i sense poder resoldre el problema.

La creació d'una aplicació complexa consta de dues fases principals: el disseny i la depuració.

Abans de començar a escriure un programa extens és necessari dedicar un temps a pensar com s'ha de resoldre el problema. L'enfocament més apropiat és la programació estructurada. Entendre els principis d'aquest tipus de programació és senzill: Divideix i venceràs. És a dir, fem el problema global i complex en petits trossos més assequibles.

Dins de la programació estructurada hi ha diferents formes d'actuar. El disseny descendent és la més utilitzada.

Un cop s'ha fet el disseny s'ha de passar a la implementació. Per això, haurem de codificar els blocs dissenyats i executar-los. En aquesta fase ens trobarem que sorgiran múltiples errors i per solucionar-los s'hauran d'aplicar els mètodes de depuració.

La detecció d'errors i la seva resolució ens obligaran a efectuar un feedback entre les fases de disseny i depuració. El codi l'haurem de repassar múltiples vegades fins a obtenir-ne el resultat desitjat.


En aquesta pràctica veurem els principals conceptes aplicables a les fases de disseny i depuració d'errors. Per si mateixos no seran suficients per poder-los aplicar a qualsevol tipus de problema, ja que és necessari disposar d' una certa habilitat i experiència en la programació, i això, solament s'aconsegueix amb el temps.


  Conceptes de programació en aquest capítol
Concepte de Programació estructurada.
Concepte de Disseny descendent.
Tècniques de depuració del codi.

  1.- La fase de disseny. Concepte de disseny descendent
La metodologia de disseny més acceptada dins la Programació Estructurada és la del disseny descendent. A partir d'un problema complex, es desenvolupa en blocs operatius enniuats que cada cop seran més concrets. Cadascun d'aquests blocs serà una funció que rebrà paràmetres i retornarà valors.

A la vegada cada bloc es subdivideix en altres blocs que també seran funcions que rebran paràmetres i retornaran valors, i així successivament.

D'aquesta forma s'aconsegueix passar d'un bloc inicial més abstracte a uns altres blocs en nivells inferiors enniuats, més concrets.

Vegem-ho millor amb un exemple:

Suposem que desitgem fer un programa que serveixi per calcular la nota mitjana d'un grup d'alumnes.

De cada alumne tenim les seves notes parcials i la ponderació dins un array amb la següent estructura:

var dades = new Array (
Grup; nNotes; pondNota1; pondNota2; pondNota3; .....
nomAlumne1; nota1; nota2; nota3; ...
nomAlumne2; nota1; nota2; nota3; ...
.....
);


Desitgem extreure la informació d'aquest array de forma que s'obtingui finalment la nota mitjana global de tot el grup.

A grans trets, el nivell d'anàlisi més elevat i més abstracte constaria dels següents passos:

1. Llegir el nom del grup i posar-lo en una variable.
2. Llegir el número de notes i posar-les en una variable.
3. Llegir la ponderació de cada nota i posar-la en una variable-array.
4. Obtenir la nota mitjana de tot el grup.
5. Mostrar la nota mitjana de tot el grup.


El punt 4 representa un concepte molt extens, la seva implementació s'ha de desglossar en apartats més senzills. Seria convenient aïllar-lo i resoldre'l a part mitjançant una funció especialitzada en aquesta tasca.

En un primer nivell de concreció el punt 4 el podem dividir en:

4.1. Obtenir la nota mitjana d'un alumne.
4.2. Acumular la nota mitjana de tots els alumnes.
4.3. Repetir els passos 4.1 i 4.2 fins a l'últim alumne.
4.4. Dividir la suma acumulada de notes mitjanes pel nombre d'alumnes.
4.5. Retornar la nota mitjana de tots els alumnes.


Tots els apartats 4.x indicats prèviament seran una funció que rebrà com a paràmetres el número de notes per alumne i la ponderació de cada nota. Un cop efectuats els passos corresponents, retornarà la nota mitjana de tots els alumnes.

L'apartat 4.1, també és complex i per tant, també el farem més concret mitjançant una altra funció més específica, amb les mateixes condicions que l'anterior.

En un segon nivell de concreció el punt 4.1 anterior es pot dividir en:

4.1.1. Obtenir el nom de l'alumne
4.1.2. Obtenir una nota de l'alumne i acumular-la a una variable.
4.1.3. Repetir el pas anterior fins a l'última nota.
4.1.4. Retornar el valor de la nota ponderada mitjana de l'alumne.


Finalment, el pas 4.1.2 anterior també el podem especificar mitjançant una altra funció en un nivell de concreció més específic. Per tant, en un tercer nivell de concreció, el pas 4.1.2 es pot dividir en:

4.1.2.1. Obtenir una nota de l'alumne i multiplicar-la per la ponderació.
4.1.2.2. Retornar la nota de l'alumne amb la ponderació.


Observem que s'ha anat del més abstracte al més concret. És a dir, hem desglossat el problema general en petits problemes, cada cop més assequibles. Cada nivell de concreció que s'aprofundeix està format per una o més funcions i cada funció rep uns paràmetres i retorna un resultat.

Tot i que no se n'ha parlat fins ara, aquest mètode és el que s'ha utilitzat en tot el curs. Però, per a problemes molt més complexos, aquest sistema es torna ineficaç. És en aquesta situació on es fa necessari aplicar els conceptes de la POO (Programació Orientada a Objectes), que ja no s'explicarà aquí per la seva gran extensió.

Les versions actuals de JavaScript no implementen la POO completament (tot i que constantment es treballa amb mètodes i propietats d'objectes) encara que mitjançant la propietat prototype és possible crear models equivalents a les classes de la POO.
 
2.- La fase de Depuració del codi
Un cop efectuada la fase de disseny indicada a l'apartat anterior, és necessari convertir cada nivell de concreció en les funcions corresponents mitjançant el codi JavaScript i provar el seu funcionament. És a dir, hem de codificar el disseny efectuat.

És en aquest moment que ens apareixen els errors, generalment inevitables quan el codi és mitjanament extens. Ara és quan hem de fer la depuració del codi. En aquesta fase tenim dos tipus d'errors: els errors de sintaxi i els errors de disseny.

Errors de sintaxi.
Els errors de sintaxi són els originats per la introducció incorrecta de les ordres. Aquests tipus d'errors ens els detecta el mateix navegador i són deguts, generalment, a errades de tecleig a l'hora d'escriure els comandaments o a errors per paritats incorrectes en escriure { } , ( ) o " ", etc. La forma d'indicar l'existència d'un d'aquests errors és diferent per IE o NN.

IE ens mostra el símbol a l'esquerra de la barra d'estat. En fer clic a sobre del símbol apareix una finestra amb el número de línia i el tipus d'error.

NN ens mostra el text a la barra d'estat del navegador. Llavors, hem d'escriure el text 'javascript:' a la barra d'adreces del navegador i ens apareixerà una finestra amb la indicació del número de línia que ha provocat l'error i el tipus d'error.

Un cop sabem el tipus d'error i número de línia hem de mirar de trobar l'error a la línia indicada i solucionar-lo. Aquest pas pot ser complex, ja que a vegades l'error no es troba en la línia indicada sinó en una línia anterior (per exemple, obrir unes cometes i no tancar-les, o un parèntesi, etc.). També es pot donar el cas que s'hagin produït múltiples errors. En aquesta situació, és aconsellable solucionar el primer error i tornar a executar. Moltes vegades els següents errors són conseqüència del primer de tots.

Errors de disseny.
Un cop hem solucionat tots els error de sintaxi, hem de comprovar si el nostre programa fa el que n'esperem. Si no és així, vol dir que tenim errors de disseny. Aquests tipus d'errors són difícils de localitzar i, generalment, es fa necessari efectuar una anàlisi del codi pas a pas. Els llenguatges de programació convencionals disposen dels programes debugger o depuradors que permeten efectuar una anàlisi detallada del funcionament del programa.

La forma de depurar el codi per trobar els errors de disseny pot ser mitjançant "xivatos" o mitjançant el depurador.

Els "xivatos" consisteixen en trossos de codi afegits dins el codi a depurar per mostrar, estàticament (aturant l'execució del codi) o dinàmicament (sense aturar l'execució del codi) el valor de variables en punts determinats de la seqüència d'execució.

El "xivato" estàtic utilitzat habitualment és el mètode alert() i el dinàmic més habitual és la barra d'estat (window.status).

El següent exemple de codi correspon a la funció eliminaBlancsExtrems() utilitzada al mòdul 7, pràctica 2, apartat 1. S'hi ha introduït un error de disseny intencionadament (s'ha substituït la condició cadena.charAt(0)==' ' per cadena.charAt(1)==' ' dins el primer while). Aquest error provoca que no s'eliminin tots els espais en blanc inicials quedant-ne sempre un.

Mitjançant tres xivatos temporals implementats amb alert() podem fer el seguiment pas a pas de l'evolució de la variable cadena i determinar en quin pas funciona malament. Un cop detectat l'error de disseny i solucionat, els xivatos s'hauran d'eliminar.

En executar el codi següent, observarem com el "Xivato 1" s'activa una vegada menys que el nombre d'espais en blanc introduïts al principi. Això ens ha de fer veure que dins aquest while hi ha un error que provoca que sempre quedi un espai sense eliminar al principi.

function eliminaBlancsExtrems(cadena)
{
  while (cadena.charAt(
1)==' '){
   
alert('Xivato 1: Eliminació blancs inicials de la cadena:\n\'' + cadena + '\'');
    cadena = cadena.substring(1,cadena.length);
  }
  while (cadena.charAt(cadena.length-1)==' ') {
   
alert('Xivato 2: Eliminació blancs finals de la cadena:\n\'' + cadena + '\'');
    cadena = cadena.substring(0,cadena.length-1);
  }
 
alert('Xivato 3: Resultat final:\n\'' + cadena + '\'');
  return cadena;
}



 
La utilització de la barra d'estat ens pot servir per implementar un "xivato" que ens mostri l'estat d'algunes variables d'un programa o bé el pas per determinats llocs del programa de forma dinàmica, és a dir, sense haver de parar l'execució del programa. El següent exemple és el mateix que l'anterior, amb el mateix error.

En aquest cas, no s'atura l'execució del codi, però, a la barra d'estat del navegador ens indica cada cop que passa per l'interior d'un dels blocs while i al final veiem com ha quedat la cadena introduïda. Per cada espai eliminat al principi apareix un símbol ' * ' i per cada espai eliminat al final apareix un símbol ' + '.

Podem observar com el nombre de vegades que passa pel primer while és sempre una menys que el nombre d'espais introduïts a l'inici de la cadena. Per tant, es dedueix que aquesta part de codi no funciona correctament com a conseqüència de l'error de disseny que hi hem introduït intencionadament.

A l'igual que l'exemple anterior, un cop detectat i solucionat l'error, s'han d'eliminar els "xivatos" introduïts.

function eliminaBlancsExtrems(cadena)
{
  while (cadena.charAt(
1)==' '){
   
window.status += " * ";
    cadena = cadena.substring(1,cadena.length);
  }
  while (cadena.charAt(cadena.length-1)==' ') {
   
window.status += " + ";
    cadena = cadena.substring(0,cadena.length-1);
  }
 
window.status += " Resultat: '" + cadena +"'";
  return cadena;
}

 
3.- Altres opcions de depuració.
En aquest apartat comentarem lleugerament dues utilitats interessants per efectuar la depuració de codi: el provador de codi incorporat a les eines d'aquest curs i un depurador fet en Java per Netscape.

El provador de codi que tenim en aquests curs és molt útil per provar petits blocs de codi abans d'incorporar-los dins el programa. Per utilitzar-lo, es tracta d'introduir el bloc de codi en el quadre de text, mitjançant l'escriptura directa o bé amb copiar i enganxar i prémer sobre el botó "Provar Script". Posteriorment veurem una finestra amb el resultat de l'execució del codi. Podem efectuar modificacions en el codi fins a obtenir el resultat desitjat.

Una altra opció per efectuar la depuració és la utilització d'un programa depurador, a l'estil del que s'utilitza en altres llenguatges tipus C/C++, Pascal, Visual Basic, etc. Aquest depurador l'ofereix Netscape i solament funciona en aquest navegador. A més, és imprescindible tenir disponible el Java per al navegador (compte, el NN6.x no el porta incorporat per defecte i s'ha de descarregar de la web per instal·lar-lo).

Aquest depurador el podeu trobar a l'adreça http://developer.netscape.com/software/jsdebug.html, disponible per a vàries versions del navegador NN. Per si no hi fos, aquí en teniu una de les primeres versions, la versió JavaScript Debugger 1.1 per a NN 4.0 o superior.

Per utilitzar-lo l'hem de descomprimir dins una carpeta i amb el NN obrir el fitxer "jsdebugger.html" . Automàticament s'executa un programa Java que ofereix les opcions de depuració.

A la finestra del navegador NN s'ha d'obrir la pàgina HTML que conté el codi JavaScript que volem depurar. Aquesta finestra serà la que utilitzarem per executar el codi. Posteriorment, dins la finestra del debugger hem d'obrir la mateixa pàgina HTML. Automàticament quedaran identificades les parts de codi JavaScript diferenciant-lo del codi HTML mitjançant una barra lateral de color groc.

En el tros de codi senyalitzat amb la barra lateral podrem indicar el punts de parada de l'execució (breakpoints). Quan executem el codi dins la finestra del navegador NN corresponent als llocs on hi hagi un breakpoint, aquest s'aturarà i ens permetrà efectuar la visualització del valor de les variables, executar pas a pas, etc.

S'ha de tenir en compte que el depurador que tenim disponible aquí reconeix les instruccions del NN4. Per a d'altres navegadors superiors de Netscape és necessari descarregar el depurador corresponent si desitgem que es reconeguin les noves prestacions aportades. Si el que volem depurar és codi que no implementi objectes propis d'un determinat navegador, aquest depurador ens serà perfectament vàlid.

Les dues eines indicades permeten més opcions que les que s'han comentat. Però, aquí no és possible descriure-les completament. Amb la pràctica es van descobrint totes les seves possibilitats.