Massimo Mirotti

Custom software

Welcome

Progettazione di un software

Per scrivere software di qualità anche semplici è necessario organizzarsi e non buttarsi sull’implementazione del codice. Questo permette di concentrare le risorse dove servono e ridurre al minimo le modifiche significative del codice una volta terminato il progetto.

 

Il primo punto fondamentale della progettazione di un software è la definizione con il cliente dei suoi requisiti. I requisiti possono essere funzionali oppure non-funzionali, e definiscono rispettivamente:

  • I compiti che il programma deve svolgere (funzionali)
  • Le sue caratteristiche di performance, usabilità e manutenibilità (non-funzionali)

I requisiti vengono definiti dal cliente col supporto del tecnico informatico.
Nei requisiti funzionali rientrano tutte le informazioni riguardo allo scopo del software. Partendo dal formato di Input dei dati, definendo il comportamento nei casi limite e nelle eccezioni, finendo con le modalità di salvataggio dei dati e l’interazione con l’utente.
Nei requisiti non-funzionali rientrano tutti i vincoli di

  • performance richieste al software;
  • il suo livello di manutenibilità (è quindi importante conoscere la vita stimata del programma e se sono previste delle modifiche);
  • Che tipo di interazione con l’utente è prevista (CLI o GUI);
  • Dimensioni tipiche e massime degli input;
  • Piattaforme per cui il software deve essere scritto;
  • Tempo a disposizione per il suo sviluppo (per definire i costi);
  • Linguaggio di programmazione;
  • Algoritmi utilizzati per raggiungere il risultato;

 

Un’altro passo fondamentale da portare avanti con la scrittura del codice è il testing. Questo deve essere eseguito durante e dopo lo sviluppo del software. L’ Acceptance testing” è quello svolto dal cliente che determina se il software esegue o meno le operazioni richieste rientrando nei requisiti. Lo “Unit testing” invece riguarda le singole unità del software e serve allo sviluppatore per controllare ogni pezzo di codice.
Il testing può essere:

  • Black-box: basato solo sui requisiti e di un software;
  • White-box: progettato osservando il codice;

 

Definire i requisiti, e le modalità di testing permette anche di stimare correttamente il costo di un software in termini di ore di lavoro per svilupparlo; dunque definire le tempistiche in cui questo software sarà pronto.

Patterns

Un Design Pattern in generale descrive un problema in cui si incorre spesso nell’ambiente di lavoro, e descrive l’idea di base che sta dietro alla soluzione di quel problema, in modo tale che sia possibile riutilizzare sempre questa soluzione, senza dover risolvere il problema nuovamente ogni volta.

I pattern, per il loro scopo, sono spesso l’astrazione di un problema e della sua soluzione in modo tale che sia possibile utilizzarli in molti ambiti e non specificatamente in una sola situazione.
La struttura dei pattern è normalmente sempre la stessa, sono composti da:

  • Un nome: identifica il pattern;
  • Un problema: descrive il problema che quel pattern vuole risolvere;
  • Una soluzione: spiega la soluzione del problema;
  • Le conseguenze: una sezione per comprendere i costi e i benefici di quel pattern e le possibili alternative

Molti pattern esistono già e ci permettono di trovare soluzioni standard, quindi abbondantemente testate, a problemi comuni; qui sotto una lista dei pattern più conosciuti e più utilizzati nell’ambito della programmazione ad oggetti:

I Pattern sono molto potenti, oltre che per trovare soluzioni ai problemi, anche e soprattutto per migliorare il lavoro di squadra all’interno di un gruppo di sviluppatori. Implementare un pattern significa scrivere del codice con una logica standard, molto utilizzata ed ampiamente documentata, inoltre rende molto più semplice la comunicazione tra le persone che, con il solo nome identificativo del pattern, sotto-intendono molte informazioni per risolvere i problemi.

La repository presente a questo link:            https://github.com/LeoMirots/Patterns
contiene il codice sorgente e la documentazione di un progetto d’esempio che implementa alcuni dei patterns sopra citati.

Algoritmi di ordinamento

Oggi presento un file in linguaggio C, che implementa i principali algoritmi di ordinamento ed espone il loro ragionamento logico.

Un algoritmo di ordinamento è una procedura iterativa che permette di scambiare gli elementi di un vettore correggendo la loro posizione in modo da rispettare l’ordine crescente o decrescente rispetto ad una chiave. Ogni algoritmo presentato in questo codice ha i suoi punti deboli, ma sono tutti molto efficienti, sono presentati i seguenti algoritmi: naive sort, bubble sort, insert sort, quick sort e merge sort.

link del codice: https://github.com/LeoMirots/Sort

LinkedList

Con questo post presento una libreria con implementate alcune funzioni per gestire le liste.

La lista è una struttura dati astratta che permette di memorizzare dei dati, di qualsiasi tipo essi siano, in modo dinamico, ovvero la memoria utilizzata non è necessariamente contigua. Questo è un vantaggio quando ho grandi quantità di dati da salvare, perché anche se le celle di memoria che ho a disposizione per salvare i dati non sono in sequenza, con una lista riesco comunque a raggiungere il mio obbiettivo: quando devo memorizzare un numero considerevole di dati, potrei non avere sufficiente memoria heap sequenziale dove immagazzinare le mie informazioni, le liste riescono ad ovviare a questo problema.

Funzionano con una struttura fondamentale che contiene l’elemento da memorizzare e un puntatore all’elemento successivo, in questo modo il blocco di dati viene diviso in singoli container con 1 elemento ciascuno. La memoria dunque non viene allocata per tutto l’array di dati, ma solo per il singolo container, senza aver bisogno di aver a  disposizione celle contigue di memoria. I singoli container possono essere salvati in modo ottimizzato, e per accedere al container successivo si segue il puntatore salvato all’interno di quello corrente. Tutto ciò si traduce in un costo computazionale per l’inserimento di un elemento in una lista sempre pari a O(1).

E’ una struttura astratta e può essere applicata a ogni tipo di dato, dai numeri, alle stringhe, fino a strutture dati più complesse, ovviamente maggiore sarà la dimensione del dato da memorizzare, maggiore sarà la dimensione del singolo container.

I file della libreria si possono scaricare a questo link: https://github.com/LeoMirots/Lists