Sistemi e Tecnologie Informatiche Requisiti per la realizzazione di un buon programma Realizzare un programma Cosa deve fare? A che serve? Su quali sistemi dovrà funzionare? Quali tecnologie adopererà? Progettiamone una implementazione … Implementiamolo! Ora, assicuriamoci che funzioni correttamente Un po di tempo dopo … “Avrei bisogno di questa funzione. Lo so che inizialmente non era prevista ma il programma ci guadagnerebbe molto se la implementassimo” “Il colore delle finestre, rosa pallido, non è molto azzeccato. Potremmo provare uno sfondo grigio a pois rossi?” Ciclo di vita dei programmi Descrive le attività fondamentali alla realizzazione di un programma: Specifica dei requisiti Scelta del sistema di calcolo Progetto Implementazione Test e correzione Manutenzione del codice Requisiti per un buon programma Correttezza Leggibilità Efficienza Parametricità Modificabilità Portabilità Requisiti per un buon programma Correttezza Assicurarsi che il programma restituisca risultati corretti in tutti i possibili casi di esecuzione previsti (e.g., un algoritmo di ordinamento deve restituire sempre un elenco ordinato) Leggibilità Adoperare uno stile di programmazione che ne semplifichi la comprensione ed, al contempo, documentare opportunamente il codice sorgente ed il progetto nella sua interezza (e.g., evitare variabili dai nomi criptici tipo a, b, c, d, e) Requisiti per un buon programma Modificabilità Semplificare la possibilità di modificare un programma preesistente per soddisfare degli eventuali nuovi requisiti (e.g., se il colore delle finestre viene memorizzato in una sola variabile mi basterà cambiare quella per passare da rosa a grigio) Portabilità Favorire la possibilità di riutilizzare il programma realizzato su sistemi diversi da quello inizialmente utilizzato (e.g., un gioco per telefonini scritto in Java potrà funzionare su tutti i telefonini Java compatibili, anche se di marche diverse) Requisiti per un buon programma Efficienza Implementare soluzioni concettualmente e sperimentalmente efficienti rispetto ai requisiti del progetto (e.g., un programma che impiega 10 anni a terminare è probabilmente inutile) Parametricità Realizzare soluzioni generali riutilizzabili in contesti differenti. (e.g. una funzione per l’ordinamento di un elenco telefonico, se scritta opportunamente, andrà bene per ordinare un qualsiasi altro elenco di nomi) Realizzare un buon programma La possibilità di realizzare un buon programma è condizionata all’adozione di opportune metodologie di sviluppo Queste intervengono: A priori, in fase di progetto, guidando lo sviluppatore nell’adottare le scelte migliori per la realizzazione del programma A posteriori, in fase di analisi, consentendo di valutare la qualità e la correttezza di un programma già realizzato Metodologie di progettazione Top-down (dall’alto verso il basso) Decompone il problema di partenza in sottoproblemi di più semplice risoluzione Il processo di scomposizione si arresta quando si giunge a problemi elementari Bottom-up (dal basso verso l’alto) Risolve isolatamente problemi più semplici e li assembla per la risoluzione di problemi più complessi Trova applicazione nei linguaggi orientati agli oggetti (e.g., C++, Java) Progettazione top-down Vantaggi: Storicamente indicata per la risoluzione di problemi molto complessi Tali problemi possono essere suddivisi in problemi più elementari Diviene inoltre possibile ripartire più facilmente un lavoro tra diversi sviluppatori Svantaggi: Le soluzioni sviluppate sono difficilmente riutilizzabili in contesti diversi da quelli previsti originariamente La progettazione trascura l’importanza delle strutture dati Progettazione bottom-up Vantaggi: Si affrontano inizialmente problemi elementari e di semplice risoluzione I programmi così realizzati costituiranno moduli da utilizzare nella risoluzione problemi più complessi La possibilità di riutilizzare i programmi realizzati consegue direttamente dalla strategia di progetto Svantaggi: I tempi di sviluppo sono tipicamente più lunghi di quelli richiesti dalla metodologia top-down E’ più complessa da attuare Metodologie di progettazione Esercizio: Progettare un programma che acquisisca una lista di valori numerici in input e ne restituisca l’elenco ordinato 1. Leggi dati in input 2. Ordina i dati letti 3. Stampa dati ordinati 1. Alloca un array di interi Vettore 2. For i from 0 to n-1 3. Leggi da tastiera Vettore[i] 4. Ordina i dati letti 5. For i from 0 to n-1 6. Stampa Vettore[i] 1 2 3 4 5 6 7 8 9 10 11 12 13 #include<stdlib.h> #include<stdio.h> Verifica correttezza #define N 6 // Numero degli elementi da ordinare int main(void){ int vettore[N]; // Mantiene gli elementi da ordinare int scambio; // Usato come variabile temporanea effettuare lo // scambio durante l’ordinamento int minimo, i, j, pos_minimo; for(i=0; i<N; i++) // Legge gli N elementi da tastiera scanf("%d", &vettore[i]); 14 for(i=0; i<N-1; i++) { 15 pos_minimo=i; 16 minimo=vettore[i]; 17 18 // ricerca il valore minimo in Vettore[i+1..N] 19 for(j=i+1; j<N; j++) 20 if( vettore[j]<minimo ) { 21 pos_minimo=j; 22 minimo=vettore[j]; 23 } 24 25 // scambia vettore[pos_minimo] e vettore[i] 26 scambio=vettore[pos_minimo]; 27 vettore[pos_minimo]=vettore[i]; 28 vettore[i]=scambio; 29 30 } 31 32 for(i=0; i<N; i++) // Stampa gli N elementi ordinati printf("%d\n", vettore[i]); 33 34 35 return 0; 36 } Leggibilità di un programma Sviluppare programmi che siano leggibili e ben documentati presenta notevoli vantaggi: Consente di comprendere con facilità quale problema il programma risolve e con quale approccio Facilita la possibilità di condividere con altri sviluppatori le soluzioni impiegate Semplifica la possibilità di tornare a modificare in un secondo momento un programma sviluppato in passato Svantaggi: E’ una attività noiosa e, spesso, apparentemente inutile Leggibilità di un programma Esistono numerose possibilità di intervento per migliorare la leggibilità di un programma, tra queste citiamo: Formattare (indentare) il codice sorgente Utilizzare nomi di variabili autoesplicativi Commentare il codice sorgente Formattare il codice sorgente 1 2 3 4 5 6 7 8 9 10 #include<stdlib.h> #include<stdio.h> int main(void) { int beta, gamma, i, delta;i=1;delta=0; scanf("%d", &beta); while(i<=9) { scanf("%d", gamma); if( beta<gamma)delta++;beta=gamma; i++; } printf("%d\n", delta);return 0; } ??? Formattare il codice sorgente Una buona formattazione si ottiene disponendo opportunamente il codice su righe e colonne in modo da far risaltare le singole istruzioni ed il contesto nel quale queste vengono eseguite if (condizione) { istruzione1; istruzione2; } else { istruzione3; istruzione4; } void funzione (int numero) { istruzione1; istruzione2; istruzione3; } for(int i = 0; i < 5; i++) { istruzione1; istruzione2; istruzione3; } do{ istruzione1; istruzione2; istruzione3; } while (i > 0) Prima …. 1 2 3 4 5 6 7 8 9 10 #include<stdlib.h> #include<stdio.h> int main(void) { int beta, gamma, i, delta;i=1;delta=0; scanf("%d", &beta); while(i<=9) { scanf("%d", gamma); if( beta<gamma)delta++;beta=gamma; i++; } printf("%d\n", delta);return 0; } … Dopo 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include<stdlib.h> #include<stdio.h> int main(void) { int beta, gamma, i, delta; i=1; delta=0; scanf("%d", &beta); while(i<=9) { scanf("%d", &gamma); if( beta<gamma ) delta++; beta=gamma; i++; } printf("%d\n", delta); return 0; } Utilizzare nomi di variabili autoesplicativi E’ preferibile attribuire alle variabili dei nomi che aiutino a comprenderne il significato e la finalità: E.g. Definire la variabile che mantiene una somma: somma Definire un intero che mantiene un indice: indice Definire una coppia di matrici da sommare: matrice1 e matrice2 Evitare nomi criptici o incomprensibili! E.g a,b,c,d x,y,z,v,w variabile1,variabile2,variabile3 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include<stdlib.h> 1 #include<stdio.h> 2 int3main(void) { 4 5 beta, gamma, i, delta; int 6 7 i=1; 8 delta=0; 9 10 scanf("%d", &beta); 11 while(i<=9) { 12 scanf("%d", &gamma); 13 if( beta<gamma ) 14delta++; 15 16 beta=gamma; 17 i++; 18 } 19 20 printf("%d\n", delta); 21 return 0; 22 } 23 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #include<stdlib.h> #include<stdio.h> int main(void) { int ultimo_numero, penultimo_numero, int i, conta_numeri; i=1; conta_numeri=0; scanf("%d", &penultimo_numero); while(i<=9) { scanf("%d", &ultimo_numero); if( penultimo_numero<ultimo_numero ) conta_numeri++; penultimo_numero=ultimo_numero; i++; } printf("%d\n", conta_numeri); return 0; } Commentare il codice I commenti sono messaggi di testo che possono essere inseriti in un codice sorgente al fine di migliorarne la comprensibilità Non hanno alcun effettto sul funzionamento di un programma … … a patto che siano usati correttamente! In C/C++ esistono due tipologie di commenti: Commenti su una sola riga, sono preceduti dalla coppia di simboli “//” e si concludono al termine della riga stessa Commenti su più righe, sono preceduti e seguite dalle coppie di simboli “/*” e “*/”. Tutto il testo racchiuso tra questi due coppie di simboli si intende essere un commento I commenti possono essere utilizzati per : Definire lo scopo di una funzione e spiegare il significato dei suoi parametri Chiarire il ruolo di una variabile Commentare un gruppo di istruzioni 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 // Questo programma legge una sequenza di 10 numeri e calcola // quanti numeri sono maggiori del precedente. #include<stdlib.h> #include<stdio.h> int main(void){ int ultimo_numero; int penultimo_numero; int i; int conta_numeri; // ultimo numero letto // penultimo numero letto // memorizza quante volte un numero e' // maggiore del precedente // assegnazione valori iniziali alla variabile di ciclo e al contatore i=1; conta_numeri=0; scanf("%d", &penultimo_numero); // lettura del primo numero … 19 // leggo i successivi numeri: confronto ognuno con il precedente 20 while(i<=9) { scanf("%d", &ultimo_numero); // leggo un numero 21 // confronto ed eventuale incremento del contatore 22 if( penultimo_numero<ultimo_numero ) 23 conta_numeri++; 24 25 // l'ultimo numero letto diventa il penultimo, 26 penultimo_numero=ultimo_numero; 27 i++; 28 29 } 30 31 printf("%d\n", conta_numeri); // stampa risultato 32 return 0; 33 }