031.1 Lezione 1
Certificazione: |
Web Development Essentials |
---|---|
Versione: |
1.0 |
Argomento: |
031 Sviluppo Software e Tecnologie Web |
Obiettivo: |
031.1 Fondamenti di Sviluppo Software |
Lezione: |
1 di 1 |
Introduzione
I primissimi computer erano programmati attraverso un estenuante processo di inserimento di cavi. Gli scienziati informatici iniziarono presto la ricerca di modi più semplici per dare istruzioni ai computer. Questo capitolo introduce agli strumenti di programmazione. Discute i modi chiave attraverso il quale le istruzioni di testo — i linguaggi di programmazione — rappresentano i compiti che un programmatore vuole realizzare, e gli strumenti che trasformano il programma in una forma chiamata linguaggio macchina che un computer può eseguire.
Note
|
In questo testo, i termini programma e applicazione sono usati in modo intercambiabile. |
Codice Sorgente
Un programmatore normalmente sviluppa un’applicazione scrivendo una descrizione testuale, chiamata codice sorgente, del compito da assegnare alla macchina. Il codice sorgente è in un linguaggio di programmazione accuratamente definito che rappresenta ciò che il computer può fare in un’astrazione di alto livello che gli umani possono comprendere. Sono stati sviluppati anche strumenti per permettere ai programmatori e ai non programmatori di esprimere visivamente queste istruzioni, ma scrivere codice sorgente è ancora il modo predominante di programmare.
Nello stesso modo in cui un linguaggio naturale ha nomi, verbi e costruzioni per esprimere idee in modo strutturato, le parole e la punteggiatura in un linguaggio di programmazione sono rappresentazioni simboliche di operazioni che saranno eseguite dalla macchina.
In questo senso, il codice sorgente non è molto diverso da qualsiasi altro testo in cui l’autore impiega le regole stabilite di un linguaggio naturale per comunicare con il lettore. Nel caso del codice sorgente, il “lettore” è la macchina, quindi il testo non può contenere ambiguità o incoerenze, per quanto sottili.
E come ogni testo che discute in profondità qualche argomento, anche il codice sorgente deve essere ben strutturato e organizzato logicamente quando si sviluppano applicazioni complesse. Programmi molto semplici ed esempi didattici possono essere memorizzati nelle poche righe di un singolo file di testo, che contiene tutto il codice sorgente del programma. Programmi più complessi possono essere suddivisi in migliaia di file, ognuno con migliaia di linee.
Il codice sorgente delle applicazioni professionali dovrebbe essere organizzato in diverse cartelle, di solito associate a uno scopo particolare. Un programma di chat, per esempio, può essere organizzato in due cartelle: una che contiene i file di codice che gestiscono la trasmissione e la ricezione dei messaggi in rete, e un’altra cartella che contiene i file che costruiscono l’interfaccia e reagiscono alle azioni dell’utente. In effetti, è comune avere molte cartelle e sottocartelle con file di codice sorgente dedicati a compiti molto specifici all’interno dell’applicazione.
Inoltre, il codice sorgente non è sempre isolato nei propri file, in un unico linguaggio. Nelle applicazioni web, per esempio, un documento HTML può incorporare codice JavaScript per completare il documento con funzionalità extra.
Editor di codice e IDE
La varietà di modi in cui il codice sorgente può essere scritto può essere impressionante. Pertanto, molti sviluppatori approfittano di strumenti che aiutano a scrivere e testare il programma.
Il file del codice sorgente è solo un semplice file di testo. Come tale, può essere modificato da qualsiasi editor di testo, non importa quanto semplice. Per rendere più facile distinguere tra codice sorgente e testo semplice, ogni linguaggio adotta un’estensione autoesplicativa del nome del file: .c
per il linguaggio C, .py
per Python, .js
per JavaScript, e così via. Gli editor generici spesso comprendono il codice sorgente dei linguaggi popolari abbastanza bene da aggiungere corsivi, colori e rientri per rendere il codice comprensibile.
Non tutti gli sviluppatori scelgono di modificare il codice sorgente in un editor generico. Un ambiente di sviluppo integrato (IDE) fornisce un editor di testo insieme a strumenti per aiutare il programmatore a evitare errori sintattici e incoerenze evidenti. Questi editor risultano particolarmente raccomandati ai programmatori meno esperti, ma anche quelli con più esperienza li usano volentieri.
Gli IDE popolari come Visual Studio, Eclipse e Xcode gestiscono in modo intelligente ciò che il programmatore digita, suggerendo spesso le parole da usare (completamento automatico) e verificando il codice in tempo reale. Gli IDE possono anche offrire debugging e test automatici per identificare i problemi ogni volta che il codice sorgente cambia.
Alcuni programmatori più esperti optano per editor meno intuitivi come Vim, che offrono maggiore flessibilità e non richiedono l’installazione di pacchetti aggiuntivi. Questi programmatori usano strumenti esterni, standalone, per aggiungere le caratteristiche che sono integrate quando si usa un IDE.
Gestione del Codice
Sia in un IDE sia usando strumenti standalone, è importante impiegare un qualche tipo di version control system (VCS). Il codice sorgente è in costante evoluzione perché i difetti imprevisti devono essere corretti e i miglioramenti devono essere incorporati. Una conseguenza inevitabile di questa evoluzione è che le correzioni e i miglioramenti possono interferire con altre parti di applicazioni in una base di codice ampia. Gli strumenti di controllo di versione come Git, Subversion e Mercurial registrano tutti i cambiamenti fatti al codice e chi ha fatto il cambiamento, permettendo di rintracciare ed eventualmente recuperare da una modifica non riuscita.
Inoltre, gli strumenti di controllo di versione permettono a ogni sviluppatore del team di lavorare su una copia dei file di codice sorgente senza interferire con il lavoro degli altri programmatori. Una volta che le nuove versioni del codice sorgente sono pronte e testate, le correzioni o i miglioramenti fatti a una copia possono essere incorporati dagli altri membri del team.
Git, il sistema di controllo di versione più popolare, permette a molte copie indipendenti di un repository di essere mantenute da persone diverse, che condividono le loro modifiche come desiderano. Tuttavia, che si usi un sistema di controllo di versione decentralizzato o che sia centralizzato, la maggior parte dei team mantiene un repository di fiducia sul cui codice sorgente e risorse si può fare affidamento. Diversi servizi online offrono la memorizzazione di repository di codice sorgente. I più popolari di questi servizi sono GitHub e GitLab, ma vale la pena menzionare anche Savannah del progetto GNU.
Linguaggi di Programmazione
Esiste una grande varietà di linguaggi di programmazione; ogni decennio ha visto l’invenzione di nuovi. Ogni linguaggio di programmazione ha le sue regole e viene raccomandato per scopi particolari. Anche se i linguaggi mostrano differenze superficiali nella sintassi e nelle parole chiave, ciò che li distingue veramente sono gli approcci concettuali che li rappresentano, conosciuti come paradigmi.
Paradigmi
I paradigmi definiscono le premesse su cui si basa un linguaggio di programmazione, soprattutto per quanto riguarda il modo in cui il codice sorgente dovrebbe essere strutturato.
Lo sviluppatore parte dal paradigma del linguaggio per formulare i compiti che la macchina deve eseguire. Questi compiti, a loro volta, sono espressi simbolicamente con le parole e le costruzioni sintattiche offerte dal linguaggio.
Il linguaggio di programmazione è procedurale quando le istruzioni presentate nel codice sorgente sono eseguite in ordine sequenziale, come la sceneggiatura di un film. Se il codice sorgente è segmentato in funzioni o subroutine, una routine principale si occupa di chiamare le funzioni in sequenza.
Il codice seguente è un esempio di linguaggio procedurale. Scritto in C, definisce variabili per rappresentare il lato, l’area e il volume di forme geografiche. Il valore della variabile side
viene assegnato in main()
, che è la funzione invocata quando il programma viene eseguito. Le variabili area
e volume
sono calcolate nelle subroutine square()
e cube()
che precedono la funzione principale:
#include <stdio.h>
float side;
float area;
float volume;
void square(){ area = side * side; }
void cube(){ volume = area * side; }
int main(){
side = 2;
square();
cube();
printf("Volume: %f\n", volume);
return 0;
}
L’ordine delle azioni definite in main()
determina la sequenza degli stati del programma, caratterizzati dal valore delle variabili side
, area
e volume
. L’esempio termina dopo aver visualizzato il valore di volume
con l’istruzione printf
.
D’altra parte, il paradigma della programmazione orientata agli oggetti (OOP) ha come caratteristica principale la separazione dello stato del programma in sotto-stati indipendenti. Questi sotto-stati e le operazioni associate sono gli oggetti, così chiamati perché hanno un’esistenza più o meno indipendente all’interno del programma e perché hanno scopi specifici.
I diversi paradigmi non limitano necessariamente il tipo di compito che può essere eseguito da un programma. Il codice dell’esempio precedente può essere riscritto secondo il paradigma OOP usando il linguaggio C++:
#include <iostream>
class Cube {
float side;
public:
Cube(float s){ side = s; }
float volume() { return side * side * side; }
};
int main(){
float side = 2;
Cube cube(side);
std::cout << "Volume: " << cube.volume() << std::endl;
return 0;
}
La funzione main()
è ancora presente. Ma ora c’è una nuova parola, class
, che introduce la definizione di un oggetto. La classe definita, chiamata Cube
, contiene le proprie variabili e subroutine. In OOP, una variabile è anche chiamata attributo e una subroutine è chiamata metodo.
Va oltre lo scopo di questo capitolo spiegare tutto il codice C++ dell’esempio. Ciò che è importante per noi qui è che Cube
contiene l’attributo side
e due metodi. Il metodo volume()
calcola il volume del cubo.
È possibile creare diversi oggetti indipendenti dalla stessa classe, e le classi possono essere composte da altre classi.
Tenete a mente che queste stesse caratteristiche possono essere scritte in modo diverso e che gli esempi in questo capitolo sono eccessivamente semplificati. C e C++ hanno caratteristiche molto più sofisticate che permettono costruzioni molto più complesse e pratiche.
La maggior parte dei linguaggi di programmazione non impone rigorosamente un paradigma, ma permette ai programmatori di scegliere vari aspetti di un paradigma o di un altro. JavaScript, per esempio, incorpora aspetti di diversi paradigmi. Il programmatore può scomporre l’intero programma in funzioni che non condividono uno stato comune tra loro:
function cube(side){
return side*side*side;
}
console.log("Volume: " + cube(2));
Anche se questo esempio è simile alla programmazione procedurale, si noti che la funzione riceve una copia di tutte le informazioni necessarie per la sua esecuzione e produce sempre lo stesso risultato per lo stesso parametro, indipendentemente dai cambiamenti che avvengono al di fuori dello scopo della funzione. Questo paradigma, chiamato funzionale, è fortemente influenzato dal formalismo matematico, dove ogni operazione è autosufficiente.
Un altro paradigma riguarda i linguaggi dichiarativi, che descrivono gli stati in cui si vuole che il sistema sia. Un linguaggio dichiarativo può capire come raggiungere gli stati specificati. SQL, il linguaggio universale per interrogare i database, è talvolta chiamato un linguaggio dichiarativo, anche se in realtà occupa una nicchia a se stante nel pantheon della programmazione.
Non esiste un paradigma universale che possa essere adottato in qualsiasi contesto. La scelta del linguaggio può anche essere limitata da quali linguaggi sono supportati sulla piattaforma o dall’ambiente di esecuzione in cui il programma sarà eseguito.
Un’applicazione web che sarà usata dal browser, per esempio, dovrà essere scritta in JavaScript, che è un linguaggio universalmente supportato dai browser. (Alcuni altri linguaggi possono essere usati perché forniscono convertitori per creare JavaScript). Quindi per il browser web - a volte chiamato client side o front end dell’applicazione web - lo sviluppatore dovrà usare i paradigmi consentiti in JavaScript. Il lato server o back end dell’applicazione, che gestisce le richieste dal browser, è normalmente programmato in un linguaggio diverso; PHP è il più popolare per questo scopo.
Indipendentemente dal paradigma, ogni linguaggio ha librerie precostituite di funzioni che possono essere incorporate nel codice. Le funzioni matematiche - come quelle illustrate nel codice di esempio - non hanno bisogno di essere implementate da zero, poiché il linguaggio ha già la funzione pronta all’uso. JavaScript, per esempio, fornisce l’oggetto Math
con le operazioni matematiche più comuni.
Anche funzioni più specializzate sono di solito disponibili dal fornitore del linguaggio o da sviluppatori di terze parti. Queste librerie di risorse extra possono essere in forma di codice sorgente; cioè, in file extra che sono incorporati nel file in cui saranno usati. In JavaScript, l’incorporazione è fatta con import from
:
import { OrbitControls } from 'modules/OrbitControls.js';
Questo tipo di importazione, in cui la risorsa incorporata è anche un file di codice sorgente, è usato più spesso nei cosiddetti linguaggi interpretati. I linguaggi compilati permettono, tra le altre cose, l’incorporazione di caratteristiche precompilate nel linguaggio macchina, cioè le librerie compilate. La prossima sezione spiega le differenze tra questi tipi di linguaggi.
Compilatori e Interpreti
Come già sappiamo, il codice sorgente è una rappresentazione simbolica di un programma che deve essere tradotto in linguaggio macchina per essere eseguito.
Grosso modo, ci sono due modi possibili di fare la traduzione: convertire il codice sorgente in anticipo per l’esecuzione futura, o convertire il codice al momento della sua esecuzione. I linguaggi della prima modalità sono chiamati linguaggi compilati e i linguaggi della seconda modalità sono chiamati linguaggi interpretati. Alcuni linguaggi interpretati prevedono la compilazione come opzione, in modo che il programma possa eseguirsi più velocemente.
Nei linguaggi compilati, c’è una chiara distinzione tra il codice sorgente del programma e il programma stesso, che sarà eseguito dal computer. Una volta compilato, il programma di solito funziona solo sul sistema operativo e sulla piattaforma per cui è stato compilato.
In un linguaggio interpretato, il codice sorgente stesso è trattato come il programma, e il processo di conversione in linguaggio macchina è trasparente al programmatore. Per un linguaggio interpretato è comune chiamare il codice sorgente uno script. L’interprete traduce lo script nel linguaggio macchina per il sistema su cui viene eseguito.
Compilazione e Compilatori
Il linguaggio di programmazione C è uno dei più noti esempi di linguaggio compilato. I maggiori punti di forza del linguaggio C sono la sua flessibilità e le sue prestazioni. Sia i supercomputer ad alte prestazioni sia i microcontrollori negli elettrodomestici possono essere programmati in linguaggio C. Altri esempi di linguaggi compilati popolari sono C++ e C# (C sharp). Come suggeriscono i loro nomi, questi linguaggi sono ispirati al C, ma includono caratteristiche che supportano il paradigma orientato agli oggetti.
Lo stesso programma scritto in C o C++ può essere compilato per diverse piattaforme, richiedendo poco o nessun cambiamento al codice sorgente. È il compilatore che definisce la piattaforma di destinazione del programma. Ci sono compilatori specifici per piattaforma così come compilatori multipiattaforma come GCC (che sta per GNU Compiler Collection) che possono produrre programmi binari per molte architetture diverse.
Note
|
Ci sono anche strumenti che automatizzano il processo di compilazione. Invece di invocare direttamente il compilatore, il programmatore crea un file che indica i diversi passi di compilazione da eseguire automaticamente. Lo strumento tradizionale usato per questo scopo è |
Il processo di compilazione non sempre genera un programma binario in linguaggio macchina. Ci sono linguaggi compilati che producono un programma in un formato genericamente chiamato bytecode. Come uno script, il bytecode non è in un linguaggio specifico della piattaforma, quindi richiede un programma interprete che lo traduca in linguaggio macchina. In questo caso, il programma interprete è chiamato semplicemente runtime.
Il linguaggio Java adotta questo approccio, così i programmi compilati scritti in Java possono essere usati su diversi sistemi operativi. Nonostante il suo nome, Java non è collegato a JavaScript.
Il bytecode è più vicino al linguaggio macchina che al codice sorgente, quindi la sua esecuzione tende a essere relativamente più veloce. Poiché c’è ancora un processo di conversione durante l’esecuzione del bytecode, è difficile ottenere le stesse prestazioni di un programma equivalente compilato in linguaggio macchina.
Interpretazione e Interpreti
Nei linguaggi interpretati come JavaScript, Python e PHP il programma non ha bisogno di essere precompilato, rendendo più facile lo sviluppo e la modifica. Invece di compilarlo, lo script viene eseguito da un altro programma chiamato interprete. Di solito, l’interprete di un linguaggio prende il nome dal linguaggio stesso. L’interprete di uno script Python, per esempio, è un programma chiamato python
. L’interprete JavaScript è molto spesso il browser web, ma gli script possono anche essere eseguiti dal programma node
al di fuori di un browser. Poiché viene convertito in istruzioni binarie ogni volta che viene eseguito, un programma in linguaggio interpretato tende a essere più lento di un equivalente in linguaggio compilato.
Nulla impedisce che la stessa applicazione abbia componenti scritti in linguaggi diversi. Se necessario, questi componenti possono comunicare attraverso un’interfaccia di programmazione dell’applicazione (API) reciprocamente comprensibile.
Il linguaggio Python, per esempio, ha capacità molto sofisticate di data mining e tabulazione dei dati. Lo sviluppatore può scegliere Python per scrivere le parti del programma che si occupano di questi aspetti e un altro linguaggio, come C++, per eseguire l’elaborazione numerica più pesante. È possibile adottare questa strategia anche quando non ci sono API che permettono la comunicazione diretta tra i due componenti. Il codice scritto in Python può per esempio generare un file nel formato appropriato per essere usato da un programma scritto in C++.
Anche se è possibile scrivere quasi qualsiasi programma in qualsiasi linguaggio, lo sviluppatore dovrebbe adottare quello che è più in linea con lo scopo dell’applicazione. Così facendo, si beneficia del riutilizzo di componenti già testati e ben documentati.
Esercizi Guidati
-
Che tipo di programma può essere usato per modificare il codice sorgente?
-
Che tipo di strumento aiuta a integrare il lavoro di diversi sviluppatori nella stessa base di codice?
Esercizi Esplorativi
-
Supponiamo che vogliate scrivere un gioco in 3D da eseguire nel browser. Le applicazioni web e i giochi sono programmati in JavaScript. Anche se è possibile scrivere tutte le funzioni grafiche da zero, è più produttivo usare una libreria già pronta per questo scopo. Quali librerie di terze parti forniscono capacità per l’animazione 3D in JavaScript?
-
Oltre a PHP, quali altri linguaggi possono essere usati sul lato server di un’applicazione web?
Sommario
Questa lezione tratta i concetti più essenziali dello sviluppo del software. Lo sviluppatore deve essere consapevole dei principali linguaggi di programmazione e del corretto scenario d’uso di ciascuno. Questa lezione affronta i seguenti concetti e procedure:
-
Cos’è il codice sorgente.
-
Editor di codice sorgente e strumenti correlati.
-
Paradigmi di programmazione procedurale, orientata agli oggetti, funzionale e dichiarativa.
-
Caratteristiche dei linguaggi compilati e interpretati.
Risposte agli Esercizi Guidati
-
Che tipo di programma può essere usato per modificare il codice sorgente?
In linea di principio, qualsiasi programma in grado di modificare il testo.
-
Che tipo di strumento aiuta a integrare il lavoro di diversi sviluppatori nella stessa base di codice?
Un sistema di controllo dei sorgenti o delle versioni, come Git.
Risposte agli Esercizi Esplorativi
-
Supponiamo che vogliate scrivere un gioco in 3D da eseguire nel browser. Le applicazioni web e i giochi sono programmati in JavaScript. Anche se è possibile scrivere tutte le funzioni grafiche da zero, è più produttivo usare una libreria già pronta per questo scopo. Quali librerie di terze parti forniscono capacità per l’animazione 3D in JavaScript?
Ci sono molte opzioni per librerie di grafica 3D per JavaScript, come threejs e BabylonJS.
-
Oltre a PHP, quali altri linguaggi possono essere usati sul lato server di un’applicazione web?
Qualsiasi linguaggio supportato dall’applicazione server HTTP usata sull’host del server. Alcuni esempi sono Python, Ruby, Perl e lo stesso JavaScript.