Friday, November 23, 2007

Linguaggi di scripting e linguaggi compilati

Il rilascio di un programma non può mai essere considerato completamente a prova di bugs. Come si sa errori possono comparire anche dopo molto tempo e possono essere difficili da individuare nei cicli di test. In effetti molti errori possono non dipendere direttamente dal programma scritto in maniera non corretta, ma possono essere causati da dati non conformi alle aspettative.
Succede così che programmi che sono in esecuzione da anni, si blocchino improvvisamente su certi input.
Un ulteriore elemento di aleatorietà è rappresentato dalle interconnessioni che un certo programma deve avere con l'esterno (altri programmi, altri database). In questo caso può essere utile modificare la condotta del programma in base alla variazione del contorno.

Tutto quanto ho scritto sopra evidenzia come la possibilità di entrare in debug non appena si verifica un errore (difficilmente riproducibile) e di risolverlo all'istante per non bloccare un certo processo sia presupposto essenziale.

Gli approcci sono diversi a seconda che si adotti una soluzione compilata o una soluzione interpretata.
Nel primo caso, la correzione dell'errore comporta la disponibilità dei sorgenti, la disponibilità delle configurazioni per il compilatore e la possibilità di usare un ambiente conforme a quando il programma era stato sviluppato. Nel secondo caso ciò che è sufficiente è disporre dei diritti di aprire il file dei sorgenti (che deve essere presente perchè interpretato); se inoltre si dispone di un ambiente in cui il programma è in esecuzione allora le attività di debug sono veramente semplici.
Non voglio dire che l'approccio compilato sia sbagliato: per certi programmi è l'unica soluzione possibile e per programmi da pacchettizzare forse l'unica; voglio solo mettere in evidenza che nel caso in cui si sviluppi all'interno di un'azienda la soluzione da preferire (soprattutto per programmi che accedono a DBMS) è la seconda.
Ho già scritto in passato sulla differenza tra Delphi e MS Access e questo post vuole fornire ulteriori spunti alla discussione.

Saturday, November 10, 2007

Tutti contro tutti

Leggendo questo articolo mi sono reso conto che le sensazioni da me provate al pensiero di usare una piattaforma al termine del suo ciclo di vita come Delphi, siano in realtà condivise da chi usa Java per sviluppare.
Nei commenti all'articolo sopra risulta interessante carpire i seguenti segnali:
Java sta diventando sempre più complesso
Java ha necessità di troppi pezzi software che devono essere messi assieme e configurati
Java richiede troppe risorse sulla macchina
Jave deve essere studiato a fondo per diventare produttivo.

I nuovi linguaggi di scripting come Ruby, PHP, Perl, hanno necessità di Apache e di un editor.
Un ragazzo che inizia ora a programmare, non può imparare una "valanga" di aspetti legati al framework e al contorno per poter essere produttivo e cominciare a vedere i risultati del suo lavoro.

Da questo punto di vista sicuramente Delphi è più avvantaggiato di Java: un ambiente unico, un solo produttore, componenti divisi per funzionalità, grande quantità di librerie e documentazione e soprattutto, come risultato, un programma compilato da trasferire semplicemente sul computer del cliente.

Thursday, August 30, 2007

Excel: VLookup + DSum insieme

Il problema del VLookup è che ritorna il primo valore che ritrova.
Il problema del DSum è che è necessario avere il range con i criteri.

La mia necessità è invece questa: fare la somma dei valori di una tabella che hanno il valore di ricerca (= valore prima colonna) uguale a quello indicato da me.
Ho creato questa UDF che consente di scandire la tabella e fare la somma dei valori della colonna indicata:
Parametri ricevuti:
- Lookup_Value = Valore da cercare
- Lookup_Table = Tabella dei valori (la prima colonna contiene la chiave di ricerca
- Column_Index = Colonna contenente i valori da sommare

Valore ritornato:
- Somma dei valori corrispondenti alla chiave passata
- Errore (#VALUE) (se il valore non è individuato)

Public Function TotRange(Lookup_Value As Variant, Lookup_Table As Range, Column_Index As Integer) As Variant
Dim riga As Integer
Dim tot
Dim trovato As Boolean
tot = 0
trovato = False
For riga = 1 To Lookup_Table.Rows.Count
If Lookup_Table.Cells(riga, 1) = Lookup_Value Then
trovato = True
tot = Lookup_Table.Cells(riga, Column_Index) + tot
End If
Next
If trovato Then
TotRange = tot
Else
TotRange = CVErr(10)
End If
End Function

Tuesday, August 07, 2007

Introduzione all'IDE di Delphi

Versione gratuita Turbo Explorer per Win32
Una volta avviato, l'IDE presenta sei zone distinte:
1. Menu e toolbar
2. Structure
3. Object Inspector
4. Project Manager
5. Tool Palette
6. L'area centrale

Descrizione delle zone
1. Menu e toolbar
Rappresenta, come per ogni programma Windows, la zona contenente l'insieme dei comandi e delle opzioni che è possibile usare all'interno di Delphi.
2. Structure
Contiene l'albero dell'attuale Form/Unit aperta. Per albero si devono intendere due cose distinte a seconda che si stia lavorando al disegno visuale della form oppure all'interno del codice. Nel primo caso sarà visualizzato l'insieme dei controlli visuali connessi tramite la relazione Parent; nel secondo caso sarà mostrata la struttura della unit del codice organizzata per categoria sintattica (funzioni, campi, etc.)
3. Object Inspector
Diviso in 2 zone contiene le proprietà e gli eventi che è possibile impostare per il componente selezionato sulla form. Da qui è possibile indicare il valore delle proprietà (nel caso di proprietà complesse esistono degli editor appositi) e degli eventi associati al componente. Da un evento si va direttamente alla finestra del codice tramite doppio click.
4. Project Manager
Rappresenta la struttura dei file del progetto. In neretto è indicato il progetto attivo. Possono essere mantenuti aperti più progetti all'interno dell'IDE e ciò risulta molto comodo durante lo sviluppo di applicazioni complesse che usano diversi moduli (dll o eseguibili).
5. Tool Palette
Contiene l'insieme degli elementi che è possibile creare. Se non è stato ancora creato alcun progetto contiene le voci che sono presenti anche all'interno del menù FileNewOther; se invece siamo sulla form contiene i componenti visuali che è possibile inserire nella form.
6. L'area centrale
All'avvio contiene la Welcome page, durante lo sviluppo contiene la grafica della form su cui stiamo lavorando, il codice associato alla form e l'History della form. Questi tre elementi sono visualizzabili uno alla volta selezionando il tab corrispondente.

Struttura di un semplice programma
Pur consentendo lo sviluppo di un insieme di programmi molto vasto (da un Web Service ad un servizio per Windows) generalmente Delphi viene usato per lo sviluppo di applicazioni VCL Form. In pratica queste applicazioni rappresentano programmi Windows (32 bit attualmente) costituiti da una o più finestre (forms) su cui sono collocati gli elementi della VCL (libreria dei componenti usata in Delphi) necessari alla realizzazione dell'interfaccia grafica. A ciascun elemento della interfaccia sono poi agganciati gli eventi necessari alla realizzazione della logica applicativa. Una volta creato un programma VCL Form, Delphi automaticamente crea i seguenti files:
- il file principale di progetto (visibile richiamando il menù contestuale View Source) dalla finestra del Project Manager o premendo Control + V una volta selezionato il nome del progetto;
- il file del codice associato alla form il cui nome è generalmente Unit1.pas
- il file contenente la definizione della form il cui nome è Unit1.dfm
In genere il file su cui si interviene maggiormente è il file Unit1.pas che conterrà tutto il codice associato ai componenti della Form1.
Nel caso che venga aggiunta una nuova form al programma, Delphi creerà due nuovi file dal nome Unit2 .pas e Unit2.dfm.

All'interno del file Unitn.pas Delphi colloca il codice Object Pascal necessario alla definizione della form. Ricordiamo che Delphi sfrutta l'Object Pascal come linguaggio di programmazione (estensione ad oggetti del Pascal). Per questo, ogni form che viene creata è derivata dalla classe della VCL TForm. L'aggiunta di nuovi componenti visuali e di nuovi eventi, rendono poi la Form creata propria del nostro programma.

Ogni Unit creata da Delphi risente delle modifiche apportate graficamente alla form. In particolare:
- l'aggiunta di un componente visuale alla form, inserisce la dichiarazione di un campo nella definizione del nuovo tipo (la classe TForm1)
- l'inserimento di un nuovo evento inserisce un metodo sempre a livello della classe TForm1 che conterrà il codice di gestione dell'evento stessoNel caso in cui il componente sia incluso in una libreria NON inserita di default all'atto della creazione della form, viene inserito dopo la parola chiave uses il nome della libreria che comprende il componente.

La variazione dei dati a livello di proprietà sulla form, può rispecchiarsi anche sulla definizione della classe TForm1. Per esempio se cambiamo il nome di un componente inserito nella form, il nome viene cambiato anche nella definizione della form stessa.
NOTA IMPORTANTE:La variazione manuale del nome di un campo precedentemente inserito nella form direttamente dal codice comporta la perdita dell'allineamento automatico tra codice e designer e ciò può creare problemi in fase di compilazione.

Per esempio:
- inserire un componente Button sulla form
- spostarsi sul codice e modificare il nome dal default Button1 a Test
eseguendo il programma sarà segnalato un primo errore di Test non trovato tra i componenti inseriti sulla form e qualora si provveda alla rimozione un successivo errore in fase di creazione della form di Class TButton non trovata.
Se invece la modifica viene fatta dall'Object inspector questa si rispecchia all'interno del codice in maniera automatica sia a livello di nome del campo che a livello di nome dei vari eventi creati.

Tuesday, May 29, 2007

REFLECTION in .NET

La possibilità di estendere un programma con dei moduli esterni che ne aumentino le funzionalità è resa possibile grazie ai potenti meccanismi della Riflessione: la capacità di introspezione messa a disposizione da .NET.

ESTENDERE UNA GERARCHIA DI CLASSI
Supponiamo di avere un programma che fa uso di una gerarchia di classi per gestire i propri dati. Supponiamo di voler dare a chiunque la possibilità di estendere la gerarchia con classi proprie. Il programma fungerà da "creatore" degli oggetti inseriti nella gerarchia delle classi.

STABILIRE LE INTERFACCE
Evidentemente le classi che dovranno essere utilizzate all'interno del programma dovranno avere un'interfaccia comune (in termini di metodi, campi e proprietà). E' necessario stabilire a priori gli elementi comuni per non dover modificare il programma successivamente. Esistono due possibili strade per stabilire gli elementi comuni alle classi:- definire una interfaccia all'interno di una libreria di classi (interfaccia che poi sarà implementata da chi vorrà realizzare una nuova classe nella gerarchia)- definire una classe radice che elenchi metodi, campi e proprietà. Tale classe può eventualmente essere una classe astratta

I PASSI DELLA IMPLEMENTAZIONE
1. Crere una Class Library (MasterLibrary) contenente la classe astratta o la definizione di interfaccia:
//CLASSE ASTRATTA
public abstract class TRoot
{
public int DatoInt;
public string DatoString;
public abstract int MetodoInt(int a);
public abstract string MetodoString(string s);
}
//INTERFACCIA
public interface IRoot
{
int MetodoInt1(int a);
string MetodoString1(string s);
}
2. Farne il Build per creare la dll. In questo modo abbiamo l'assembly contenente gli elementi essenziali per creare librerie di classi per estendere il programma
3. Nel programma che realizzeremo si dovranno utilizzare 2 metodi della System.Reflection (LoadFile e CreateInstance). Questi 2 metodi servono rispettivamente per recuperare l'assembly contenente le classi da noi definite e per creare l'istanza della classe presente all'interno dell'assembly stesso.
Il nome dell'assembly e della classe possono essere recuperati da un file di parametri usato dal programma.

ESTENDERE LA GERARCHIA DELLE CLASSI
1. Creare una Class Library includendo come Reference la MasterLibrary.dll;
2. Derivare ogni classe dalla TRoot (nel caso si usi la Classe Astratta) o dalla IRoot (nel caso si usi l'Interfaccia);
3. Implementare i metodi secondo la logica prevista;
4. Creare un file di configurazione contenente il nome dell'Assembly (.dll) completo di path ed il nome delle classi incluse al suo interno che vogliamo mettere a disposizione nel programma;

PER FINIRE
In pratica:
1. Nella MasterLibrary vengono definiti gli elementi (in termini di metodi e campi) che saranno implementati in tutte le classi che estenderanno la classe base
2. In tutte le estensioni si dovrà far riferimento alle classi definite nella MasterLibrary ereditando da quest'ultime
3. Nel programma si potrà far riferimento alle classi grazie ai metodi previsti a livello di Reflection, creando nuovi oggetti dalle classi definite all'esterno.

Sunday, May 06, 2007

Sui bravi programmatori

Riporto in inglese una frase estratta da un forum su VB estratto da Codeproject
"There are not bad languages, there are bad programmers, whatever language they use."
traduco: "Non ci sono linguaggi non buoni, ci sono programmatori non buoni, indipendentemente dal linguaggio che usano".

Vorrei riportare qui alcuni punti essenziali:
- VB ha permesso a molti (anche non professionisti) di sviluppare programmi
- VB ha indotto molti a credere che per scrivere un buon programma fosse sufficiente mettere alcuni controlli su una form senza avere alcun tipo di background scientifico per risolvere correttamente determinati problemi
- VB è stato ed è (VB.NET) un linguaggio come tanti altri che, se usato professionalmente può consentire di sviluppare ottimi programmi.

Per esperienza diretta:
- esistono linguaggi (Java per primo) che impongono dei paradigmi di programmazione che per essere compresi necessitano di una buona preparazione teorica
- qualunque linguaggio si usi la "strutturazione del codice" è fondamentale per una buona gestione dei progetti

Campi statici e variabili di classe

Ho letto questo blog e mi sono venuti alcuni dubbi che ho poi fugato facendo alcuni esempi.
Java ha sempre avuto i campi static, cioè le variabili globali a livello di classe. In Delphi questa caratteristica è stata introdotta (per rispettare .NET) dalla versione 8 (solo .NET) poi riportata nella versione per Win32.
Il dubbio che mi è sovvenuto è il seguente:
cosa succede nel caso che una classe derivi da un'altra che ha un campo static pubblico?

La risposta è la seguente:
il campo static (cioè la variabile di classe) è condivisa tra tutte le sottoclassi della classe che ha dichiarato quel campo come static. In pratica se ho queste classi:
T1 = class
class var a:integer;
...
end;
e
T2 = class(T1)
...
end;

T1.a e T2.a riferiscono la stessa variabile.

Se voglio differenziare T2.a da T1.a DEVO dichiararla nuovamente.

Questo è lo stesso comportamento di Java.

Come indicato nel post da me citato, la precedente possibilità era di quella di usare una variabile globale a livello di unit.

La situazione è ora molto più object oriented (anche per Delphi).

Friday, March 16, 2007

I Miei Blogs futuri

Vorrei, tempo permettendo, publicare una serie di blogs sui seguenti argomenti:
1- Perchè Delphi?
Perchè scegliere Delphi per programmare
2- Delphi ed MSAccess
Le differenze e i vantaggi di una scelta piuttosto che dell'altra
3- Access ed i Template di Outlook (.OFT)
Come aprire da Access un Mail Template di Outlook
4- Migrazione da Access a SQL Server
Alcune indicazioni sulla migrazione dei dati da Access a SQL server
5- Le ultime novità di Delphi
Delphi 2007 oramai è alle porte
6- Lettura del pensiero
La sera avevo un problema. La mattina trovo un Post che fa al caso mio. Incredibile.

Wednesday, January 03, 2007

RISOLTO!

Dopo una quindicina di giorni di lavoro ho risolto, con l'aiuto di tutta la famiglia Mystery Case Files - Prime Suspects. Grande e coinvolgente gioco!
Divertentissimo il finale.

Monday, January 01, 2007

Cast e ListView in Delphi

In molte applicazioni si ha la necessità di dare all'utente la possibilità di creare più oggetti della stessa classe. Questi oggetti hanno una propria vita e l'utente deve poterli selezionare per lavorare su di essi.
Una situazione classica è quella di avere una lista di tali oggetti da cui selezionare quello su cui si vuole lavorare. Sorge il problema di passare dalla selezione sulla lista all'oggetto associato.
In Win32 una lista ha una sua rappresentazione come ListView. Una riga della ListView (ListItem) è un oggetto che ha, tra le proprietà, un puntatore (Data). Questo puntatore consente di memorizzare, tra le altre cose, il riferimento all'oggetto che noi associamo alla riga della lista.
L'uso del cast consente di "leggere" il puntatore come l'oggetto che abbiamo associato alla riga.

Ecco un esempio:

Creazione dell'oggetto

var
lv:TListItem;
p:TOggetto;
begin
lv:=lvElenco.Items.add;
lv.Caption:='Oggetto '+inttostr(lvElenco.Items.Count);
//creazione dell'oggetto
p:=TOggetto.create;
//associazione dell'oggetto all'Item appena creato
lv.Data:=p;
end;

Recupero dell'oggetto associato alla riga della lista (Item):

var
obj:TOggetto;
begin
//recupero l'oggetto tramite il casting
obj:=TOggetto(Item.Data);
...
end;

Felix Colibri: Documentazione su Delphi

Ulteriore documentazione sull'uso di Delphi.
Molto ben fatta la gestione delle basi dati.