Sui banchi di scuola e nei laboratori di scuola, all’inizio del percorso di studio si è soliti studiare linguaggi di programmazione come C o C++. La scelta non è casuale e, tuttora, rappresenta una valida scelta. Il linguaggio C nasce negli anni ’70, quando l’hardware e il mondo informatico cominciava a porre dei primi significativi passi verso l’era moderna a noi più nota. Parliamo di architetture ancora semplici, con poche risorse di calcolo fondamentalmente e da cui, a livello software, di certo non ci si aspettava molto. I programmi erano semplici, progettati e realizzati dallo stesso programmatore che ne testava poi l’usabilità o che finiva per essere l’unico utilizzatore! Parliamo di software con interfacce grafiche assai primitive, spesso poco intuitive da utilizzare via tastiera piuttosto che mouse. Il C aveva un approccio a basso livello con la gestione “manuale” della memoria (vedi puntatori, allocazione statica della memoria, etc.)
Il paradigma top-down
Il paradigma di programmazione era molto simile a quello che studiano i nostri studenti: un blocco di codice singolo con la possibilità di suddividere il problema complessivo in più sottoproblemi più piccoli, attraverso l’utilizzo di funzioni e passaggio di parametri. La programmazione top-down. Hardware semplici, software semplici, linguaggi più vicini al modo di pensare del calcolatore e delle sue esigenze, piuttosto che al mondo reale. Se il consulente progettista era per forza il programmatore perché doveva studiare le strutture dati in base alle esigenze del calcolatore e del linguaggio. Utilizzare il C in team di sviluppo e software di complessità crescente diventava molto difficoltoso ma necessario per la crescente richiesta di complessità.
Se volevo creare un catalogo di alunni, dovevo pensare ad un certo numero di vettori “paralleli” per catalogare le informazioni necessarie. E se per sbaglio ci fossimo trovati ad aggiungere o togliere informazioni si sarebbe dovuto stravolgere l’intero programma. Occorreva una svolta in termini di progettazione e manutenzione del codice, portabilità su piattaforme differenti ed estensione delle funzionalità in modo semplice e non invasivo del codice esistente.
La programmazione ad oggetti
Era l’alba di una nuova era tecnologica: si affacciavano negli anni ’80 i primi calcolatori da tavolo commerciali. Era giunto il momento di una svolta anche nel paradigma di programmazione. Nasceva il C++, linguaggio più ad alto profilo del fratellino C e nato con l’intento di essere ad oggetti, finito per essere un ibrido pur sempre ambizioso. Occorreva non progettare le strutture dati per catalogare l’alunno, ma portare l’alunno dentro il programma. E questa è la vera svolta: creare un oggetto alunno con tutte le caratteristiche (gli attributi ) che vogliamo descrivano il frammento di realtà, con tutte le funzionalità (i metodi) per interagire con tali informazioni da usare in modo intuitivo da tutti, anche programmatori differenti da chi ha creato il concept iniziale. Il paradigma basato sugli oggetti consente di far interagire tra loro gli oggetti con semplici scambi di messaggi a mezzo di funzioni. Se un software molto grande è caratterizzato da tante parti, ovvero tanti oggetti, è decisamente più semplice suddividere le parti dello sviluppo senza bloccarne una in particolare. Gli oggetti, se ben progettati con le loro strutture astratte, le classi, rappresentano un enorme vantaggio per poter riutilizzare codice che risulta generico e indipendente dalle strutture e hardware. In breve:
- la OOP fornisce un supporto naturale alla modellazione del software, partendo dagli oggetti del mondo reale;
- permette una più facile gestione e manutenzione di progetti di grandi dimensioni da sviluppare anche con team grandi;
- l’organizzazione del codice favorisce la modularità e suddivisione delle responsabilità, nonché il riuso del codice in contesti diversi e debuggabilità.
Altra caratteristica saliente è l’incapsulamento. E’ un meccanismo della maggior parte dei linguaggi ad oggetti dove si limita l’accesso diretto agli elementi dell’oggetto, in particolare agli attributi, obbligando il programmatore o l’utente che va ad utilizzare una classe, ad utilizzare opportuni metodi di accesso (set e get) che possiedono codice sicuro e versatile per gestire tali attributi, senza bisogno di conoscere quali siano gli attributi veri e propri e le loro specificità. Quello dell’incapsulamento allo studente alle prime armi è un concetto che sfugge perché sarà l’autore e creatore sia delle classi sia delle strutture che vanno ad implementare tali classi. Nella realtà, è facile che uno sviluppatore sia in possesso di classi fatte da altri a mezzo di librerie che può utilizzare solo attraverso l’incapsulamento senza conoscere tutto il mondo che c’è dietro, ma solo quello che viene reso pubblico.
Altro concetto che merita attenzione è l’ereditarietà. Una caratteristica OOP che permette di specializzare e personalizzare classi esistenti (che magari sono realizzate da altri sviluppatori) aggiungendo e migliorando attributi e metodi per gestire casi specifici di quella entità descritta (es Forma-geometrica -> Quadrato; abitazione -> Villetta o Condomino)
Il linguaggio Java
Java nasce nella seconda metà degli anni ’90, quando il mondo della programmazione era ormai maturo e richiedeva strumenti nuovi. Nasce come linguaggio OOP nativo, tanto da rendere paradossalmente più difficile per un programmatore alle prime armi risolvere i classici problemini come media, ricerca o max e min con funzioni di supporto.
Java deve la sua fortuna alla Java Virtual Machine (JVM), una sorta di cuscinetto che viene installato sul sistema operativo e agisce da interprete del bytecode java dei programmi che realizziamo. Quindi, lo stesso codice Java può essere eseguito su sistemi operativi diversi e senza doverlo adattare alla piattaforma di destinazione. Un bel risultato rispetto al C/C++. Il codice dei linguaggi C like va infatti ricompilato rispetto ad ogni sistema operativo e architettura con la probabilità che non vada in porto per istruzioni e comandi non compatibili (ad esempio ricordate il system(“pause”) ? Esiste su windows ma non linux o mac). Installata la Virtual Machine della specifica macchina, il codice sarà perfettamente trasportabile, senza problemi di compatibilità. Il codice badate bene è quasi a livello sorgente, subisce una precompilazione che genera un bytecode. I
l lettore attento noterà la stranezza: ma le performance di un codice compilato direttamente possono avere le stesse performance? La risposta è no. Java sarà sempre più lento del C++ e avrà un’occupazione di memoria decisamente superiore. Non è compilato, non è interpretato come python o php, ma una via di mezzo, pur sempre accettabile.
Ma allora perché imparare Java? Dipende ovviamente da che prestazioni ci occorrono ma una cosa è certa: Java ha dei tempi di realizzazione di software complessi media nettamente vantaggiosa. Questo è merito della sua natura ad oggetti e di una JDK (Java Development Kit), la libreria di sviluppo che mette a disposizione del programmatore non solo diverse librerie standard , ma anche molti strumenti e facilitazioni, a cominciare dai suggerimenti di metodi e funzionalità, piuttosto che il debug automatico in tempo reale mentre si scrive il codice, completamente automatico e simili. In sintesi, con Java scrivere codice è quasi una passeggiata!
Senza contare che in C/C++ il programmatore deve gestire la memoria, la distruzione degli oggetti, i puntatori, e le varie strutture dinamiche con malloc e simili. Java non ha questi problemi. C’è una funzionalità Garbage Collector che spazza la memoria e libera gli oggetti inutili all’esecuzione del programma.
Ma quindi si deve installare la pesante JDK per far funzionare un software Java? No, basta la sua versione ridotta Runtime JRE (Java Runtime Environment) che contiene la JVM e l’occorrente per l’esecuzione dei bytecode.
Gli eredi di Java
Uno dei principali eredi e concorrenti di Java è senza dubbio il C# (leggi “si sciarp“). Nasce da mamma Microsoft come proprio linguaggio OOP che cercava di prendere un po’ il meglio del C++ e di Java, il tutto portato sulla piattaforma di casa Microsoft .NET (leggi dot net).
C# è un linguaggio piuttosto semplice da usare, a differenza dei suoi predecessori C e C++ che utilizzavano un linguaggio più vicino a quello “da macchina”. C# lo troviamo nei principali software di uso quotidiano: Windows, iOS e Android. Viene utilizzato per la programmazione di software e di applicazioni destinate a computer e cellulari. Come Java, è un linguaggio versatile perché è indipendente dalla piattaforma nel quale viene utilizzato ma ha forti limitazioni su Mac e Linux connesse al fattore “casa Microsoft” che per forza di cose fornisce tool e piattaforma SDK ottimizzata per Windows. Su Linux è comunque scaricabile ed utilizzabile con Visual Studio Code e si può anche azzardare una programmazione visuale con MonoDevelop, IDE di sviluppo Open Source cross platform ma con meno pretese de Visual Studio standard.
È in costante evoluzione ancora oggi da parte di Microsoft, probabilmente con meno release di Java, ma sempre in attività. Rimane un linguaggio completo anche con diversi strumenti per sviluppare su piattaforma Android.
La libreria grafica Windows Presentation Foundation (WPF) è molto interessante e performante, almeno più di quelle storiche di Java Swing e del tutto comparabili alle moderne Java FX. JavaFx ha delle caratteristiche decisamente interessanti però per l’uso congiunto di Directx e OpenGL che sfrutta a a seconda della disponibilità elaborando con la GPU! Interessante l’approccio CSS di JavaFX che rende il tutto friendly dal punto di vista della personalizzazione.
Unica forzatura è l’uso di db MS SQL di casa Microsoft mentre Java, pur sponsorizzando Oracle, rimane versatile con una varietà infinita di DBMS. Molto interessante Linq SQL che semplifica molto la gestione delle query immergendole nel codice normale.
Quale sia meglio tra C# e Java? Alcuni punti di vista differenti ma sono linguaggi all’avanguardia e con molto mercato dal punto di vista lavorativo. Se lo chiedete a me preferisco Java per le prestazioni comunque superiori e la portabilità schiacciante rispetto al collega di Redmond. Diciamo che per storia e varie eventuali, Java detiene comunque un 10% in più del mercato rispetto a C#. Java è più anzianotto e ha una varietà enorme di librerie, codice, customizzazioni varie che lo rendono appetibile per riusabilità del codice. Probabilmente C# ha una curva di apprendimento più semplice rispetto a Java ma sono comparabili tutto sommato. C# ha grande versatilità per il gaming con le Unity mentre Java per le applicazioni web Enterprise.
Quale scegliere? Dipende sempre dal contesto e anche dalle chance lavorative del proprio territorio. Ma questo vale per qualsiasi linguaggio!
Accoppiamento & Coesione
Il programmatore OOP in erba spesso stenta ad entrare nella logica della vera programmazione ad oggetti. Lo stesso studente che nei corsi di informatica affronta lo studio del C/C++ è lusingato dal tentare un approccio ibrido che mescola il modo di programmare imperativo tradizionali mischiato a qualche classe qui o li. L’approccio di tale natura è maggiormente evidente, per esperienza empirica osservata, quando si arriva alla gestione delle interfacce grafiche.
Due termini ci preme allora affrontare in questo paragrafo:
- Accoppiamento (Coupling)
- Coesione (Cohesion)
L’accoppiamento è la pratica progettuale e realizzativa più o meno accentuata per cui ci ritroviamo un software dove ci sono numerose classi fortemente dipendenti dalle altre. Questa è una caratteristica non desiderabile strettamente. E’ bene quindi progettare le classi per essere più indipendenti possibile, avvalendosi al più di altre classi in aggregazione/composizione ma che siano standard del framework JDK (es. le date, le classi di sistema ecc).
La coesione invece è la caratteristica di una classe, o meglio dei suoi metodi, di essere o meno riutilizzabili in molti contesti, di risolvere generici problemi. Il codice di buona qualità dovrebbe avere metodi, o classi, mirate ad uno scopo soltanto. In tale circostanza, è facile leggere quel codice, siamo certi che quello che c’è dietro è codice mirato a gestire le casistiche, gli input, gli output gli errori tutti di una solo determinata evidenza.
Ultima modifica 6 Aprile 2023