Capitolo 3
Il Software Iniziale (1950-1960)
Se l'hardware costituiva la struttura fisica dei primi computer, il software rappresentava l'intelligenza che li animava, permettendo di trasformare circuiti elettronici in strumenti di calcolo e di elaborazione dell'informazione. Nei primi anni dell'informatica, lo sviluppo del software era un'attività pionieristica, spesso strettamente legata alla conoscenza dettagliata dell'architettura hardware. In questo capitolo, esploreremo le prime forme di software, dai linguaggi macchina e assembly ai primi linguaggi di programmazione di alto livello e ai rudimentali concetti di sistema operativo.
3.1 Il Linguaggio Macchina:
Parlare Direttamente all'Hardware
La forma più elementare di software è il linguaggio macchina. Questo è il linguaggio nativo compreso direttamente dall'unità centrale di elaborazione (CPU) di un computer. Ogni tipo di CPU ha il proprio linguaggio macchina specifico, costituito da una sequenza di istruzioni binarie (sequenze di 0 e 1). Ogni istruzione del linguaggio macchina corrisponde a un'operazione elementare che la CPU può eseguire, come ad esempio:
- Operazioni aritmetiche: Sommare, sottrarre, moltiplicare, dividere numeri.
- Operazioni logiche: Eseguire operazioni logiche booleane (AND, OR, NOT) su bit.
- Trasferimento dati: Spostare dati tra la memoria e i registri della CPU.
- Controllo del flusso: Modificare l'ordine in cui le istruzioni vengono eseguite (salti condizionati e incondizionati).
Programmare direttamente in linguaggio macchina era un compito estremamente arduo e complesso per diverse ragioni:
- Difficoltà di lettura e scrittura: Le sequenze binarie sono difficili da interpretare e da ricordare per gli esseri umani. Un semplice programma poteva richiedere lunghe e intricate sequenze di 0 e 1.
- Dipendenza dall'architettura hardware: Il linguaggio macchina è specifico per una particolare architettura di CPU. Un programma scritto per un tipo di computer non poteva essere eseguito su un altro con un'architettura diversa.
- Alto rischio di errori: La manipolazione diretta di sequenze binarie rendeva estremamente facile commettere errori di battitura o di logica.
- Difficoltà di debugging: Individuare e correggere gli errori in un programma scritto in linguaggio macchina era un processo lungo e frustrante.
Nonostante queste difficoltà, i primi programmatori dovevano necessariamente lavorare a questo livello per far funzionare i primi computer. La programmazione in linguaggio macchina richiedeva una profonda conoscenza dell'architettura hardware del computer e una grande attenzione ai dettagli.
3.2 Il Linguaggio Assembly:
Un Passo Verso l'Astrazione
Per semplificare il compito della programmazione, fu sviluppato il linguaggio assembly.
Questo linguaggio è una rappresentazione simbolica del linguaggio macchina. Invece di utilizzare sequenze binarie, il linguaggio assembly utilizza mnemonici (brevi abbreviazioni) per rappresentare le istruzioni del linguaggio macchina e nomi simbolici per rappresentare gli indirizzi di memoria.
Ad esempio, un'istruzione in linguaggio macchina per sommare due numeri potrebbe essere rappresentata in linguaggio assembly con un mnemonico come ADD seguito dai nomi dei registri o degli indirizzi di memoria contenenti i numeri da sommare.
Per poter eseguire un programma scritto in linguaggio assembly su un computer, era necessario un programma speciale chiamato assembler. L'assembler traduce ogni istruzione in linguaggio assembly nella corrispondente istruzione in linguaggio macchina.
L'utilizzo del linguaggio assembly offriva diversi vantaggi rispetto alla programmazione diretta in linguaggio macchina:
- Maggiore leggibilità e scrivibilità: I mnemonici erano più facili da ricordare e da interpretare rispetto alle sequenze binarie.
- Utilizzo di nomi simbolici: Permetteva ai programmatori di riferirsi a indirizzi di memoria e ad altre entità utilizzando nomi simbolici invece di indirizzi numerici, semplificando la gestione della memoria e riducendo il rischio di errori.
- Maggiore produttività: La programmazione in assembly era più veloce e meno soggetta a errori rispetto alla programmazione in linguaggio macchina.
Tuttavia, il linguaggio assembly rimaneva comunque un linguaggio di basso livello, strettamente legato all'architettura hardware del computer.
I programmatori dovevano ancora avere una buona conoscenza del funzionamento interno della CPU e della memoria. Inoltre, un programma scritto in assembly per una particolare architettura non poteva essere facilmente portato su un'altra.
3.3 I Primi Linguaggi di Programmazione di Alto Livello:
Verso l'Indipendenza dall'Hardware
La crescente complessità dei problemi che si volevano risolvere con i computer e la difficoltà di programmare in linguaggi di basso livello portarono allo sviluppo dei linguaggi di programmazione di alto livello. Questi linguaggi erano progettati per essere più vicini al linguaggio umano e più indipendenti dall'architettura hardware specifica del computer. Un singolo comando in un linguaggio di alto livello poteva corrispondere a diverse istruzioni in linguaggio macchina.
Per poter eseguire un programma scritto in un linguaggio di alto livello, era necessario un programma speciale chiamato compilatore o interprete. Un compilatore traduce l'intero programma in linguaggio di alto livello in linguaggio macchina (o in un linguaggio intermedio) prima dell'esecuzione. Un interprete, invece, traduce ed esegue il programma riga per riga.
Negli anni '50, emersero alcuni dei primi e più influenti linguaggi di programmazione di alto livello:
- FORTRAN (FORmula TRANslation): Sviluppato da un team guidato da John Backus presso IBM a partire dal 1954, FORTRAN fu progettato specificamente per applicazioni scientifiche e ingegneristiche che richiedevano intensi calcoli numerici. FORTRAN offriva una sintassi più simile alla notazione matematica e forniva costrutti specifici per la manipolazione di array e matrici.
- Il suo successo fu immediato nella comunità scientifica e ingegneristica, e FORTRAN continua ad essere utilizzato ancora oggi in alcune aree della ricerca e dello sviluppo. La sua introduzione rappresentò un passo fondamentale verso la semplificazione della programmazione scientifica.
- COBOL (COmmon Business-Oriented Language): Sviluppato a partire dal 1959 da un comitato guidato da Grace Hopper, COBOL fu progettato per applicazioni aziendali e di elaborazione dati. L'obiettivo era creare un linguaggio che fosse facile da capire e utilizzare da parte dei non esperti di informatica, come i manager e gli analisti aziendali. COBOL enfatizzava la leggibilità e forniva costrutti specifici per la gestione di grandi quantità di dati, la creazione di report e l'interazione con i file. COBOL divenne rapidamente il linguaggio dominante per le applicazioni aziendali e ha mantenuto una notevole importanza per decenni. Molti sistemi legacy aziendali critici sono ancora oggi scritti in COBOL.
- LISP (LISt Processing): Sviluppato da John McCarthy al MIT nel 1958, LISP fu progettato per la ricerca sull'intelligenza artificiale e per la manipolazione di simboli e liste. La sua sintassi, basata sull'uso estensivo di parentesi, era radicalmente diversa da quella di FORTRAN e COBOL. LISP introduceva concetti innovativi come la ricorsione e il trattamento delle funzioni come dati. Nonostante non abbia raggiunto la diffusione di FORTRAN e COBOL in altri ambiti, LISP ha avuto un'influenza significativa sulla ricerca sull'intelligenza artificiale e sullo sviluppo di altri linguaggi di programmazione.
Lo sviluppo di questi primi linguaggi di alto livello rappresentò un'enorme semplificazione per i programmatori, consentendo loro di concentrarsi sulla logica del problema da risolvere piuttosto che sui dettagli dell'architettura hardware.
Questo portò a una maggiore produttività e alla possibilità di affrontare problemi più complessi con i computer.
3.4 I Primi Concetti di Sistema Operativo (Batch Processing)
Nei primi anni dell'informatica, non esistevano sistemi operativi complessi come quelli a cui siamo abituati oggi. L'interazione con il computer era spesso diretta e il programmatore doveva gestire manualmente tutte le risorse della macchina. Tuttavia, con l'aumentare della potenza e della complessità dei computer, emerse la necessità di un software che potesse gestire le risorse hardware e semplificare l'esecuzione dei programmi.
Una delle prime forme di gestione dei lavori (job) sui computer era il batch processing. In questo approccio, un insieme di lavori (ad esempio, programmi da eseguire con i relativi dati di input) veniva raccolto in un "batch". L'operatore del computer caricava il batch di lavori nel computer, che li eseguiva uno dopo l'altro in sequenza, senza l'intervento diretto del programmatore durante l'esecuzione. I risultati di ogni lavoro venivano poi prodotti come output (ad esempio, su nastro magnetico o stampante).
Il batch processing presentava alcuni vantaggi:
- Maggiore efficienza: Permetteva di utilizzare il computer in modo più continuativo, riducendo i tempi di inattività tra l'esecuzione di un lavoro e l'altro.
- Semplificazione della gestione: L'operatore doveva solo caricare il batch iniziale e poi raccogliere i risultati, senza dover interagire continuamente con il computer.
Tuttavia, il batch processing aveva anche delle limitazioni:
- Mancanza di interattività: Il programmatore non poteva interagire con il programma durante l'esecuzione. Se si verificava un errore, era necessario attendere la fine del lavoro per analizzare l'output.
- Tempi di attesa lunghi: Se un lavoro era lungo, gli altri lavori nel batch dovevano attendere il suo completamento.
Nonostante queste limitazioni, il batch processing rappresentò un primo passo verso lo sviluppo dei moderni sistemi operativi, introducendo il concetto di gestione automatica dell'esecuzione dei programmi.
3.5 Sfide e Innovazioni nello Sviluppo del Software Iniziale
Lo sviluppo del software nei primi anni dell'informatica era un'attività estremamente impegnativa. I programmatori dovevano affrontare numerose sfide:
- Hardware costoso e limitato: Le risorse hardware dei primi computer erano scarse e costose. I programmatori dovevano ottimizzare attentamente il loro codice per sfruttare al meglio la memoria e la potenza di calcolo disponibili.
- Strumenti di sviluppo rudimentali: Non esistevano gli ambienti di sviluppo integrati, i debugger sofisticati e le librerie di software a cui siamo abituati oggi. La programmazione era spesso un processo manuale e meticoloso.
- Mancanza di standardizzazione: Non esistevano standard ampiamente accettati per i linguaggi di programmazione e per le interfacce hardware, il che rendeva difficile la portabilità del software.
- Comunità di sviluppatori limitata: La comunità di programmatori era piccola e le conoscenze e le tecniche di programmazione erano in continua evoluzione.
Nonostante queste difficoltà, i pionieri del software dimostrarono una grande creatività e ingegno nello sviluppare i primi programmi e nel gettare le basi per la disciplina dell'ingegneria del software. L'introduzione dei linguaggi di alto livello, sebbene inizialmente accolta con scetticismo da alcuni che preferivano il controllo offerto dai linguaggi di basso livello, si rivelò un passo fondamentale per rendere la programmazione più accessibile e produttiva.
Il software iniziale degli anni '50 fu caratterizzato dalla transizione dalla programmazione direttamente in linguaggio macchina all'utilizzo di linguaggi assembly e, soprattutto, dei primi linguaggi di programmazione di alto livello come FORTRAN, COBOL e LISP. Questi linguaggi rappresentarono un'importante astrazione dall'hardware, semplificando il compito della programmazione e aprendo la strada a nuove applicazioni per i computer. Parallelamente, emersero i primi concetti di sistema operativo, come il batch processing, che miravano a migliorare l'efficienza nell'utilizzo delle preziose risorse hardware. Le sfide nello sviluppo del software erano considerevoli, ma l'ingegno e la determinazione dei primi programmatori posero le fondamenta per la successiva esplosione del mondo del software.