Semplici regole per software architect

Per sviluppare bene un software, vi sono tante regole da seguire. Se vi danno la responsabilità di una architettura, vi sono però tre piccoli principi che mi hanno salvato più di una volta. Senza pretendere che essi valgano per tutti, ma conscio del fatto che in oltre 15 anni di programmazione ad oggetti mi hanno salvato più di una volta, eccoli qui:

Principio1 La duplicazione del codice è la spia di un potenziale problema. Non sempre è possibile rimuovere codice duplicato, ma se si abusa troppo con Ctrl-C/Ctrl-V si rischia di ritrovarsi presto con tanto lavoro da fare appena sarà richiesta una minima modifica o manutenzione. Ridurre il codice all’osso però come vedremo non è sempre consigliabile…

Principio2 Scrivere moduli software isolati è molto utile. La duplicazione del codice è il modo migliore di ottenere l’isolamento, ma ovviamente rende la manutenzione costosa (come indicato sopra). Invece il codice duplicato è stupendamente isolato: la modifica di A non impatterà quasi mai su B. Il modo migliore per scrivere codice isolato è…scrivere test di unità! Difatti se un componente singolo deve essere testabile, è necessario che sia possibile invocarlo in modo isolato dal resto del contesto.

E’ molto importante sottolineare qui che i test di unità devono testare solo singoli elementi che abbiano business logic. Per esempio testare che una query ritorni esattamente i record attesi è molto utile ma non è esattamente un test di unità. Ho impiegato parecchio tempo a capire questo concetto e ve lo espongo meglio.

Se la vostra query accetta N parametri opzionali, voi volete testare SOLTANTO che quando gli passate A,B,C essa esegua la query esatta che mi aspetto, ma non il risultato della query. Difatti testare il risultato della query equivale a fare un test di integrazione per testare la base dati o il database. Ma gli errori sulla base dati o sul db non sono sicuramente di competenza del vostro test di unità (a meno che il vostro software non sia proprio… un database… :)

Invece voi dovete testare che la codifica dei campi di una form sia corretta e arrivi (per esempio) al vostro EJB. Che il vostro EJB magari componga correttamente la query per tutte le combinazioni dei parametri di ingresso.

Principio3 Di tutti i design pattern, imparate per primo il prinicipio di HollyWood o inversione del controllo. E’ molto importante capire che la programmazione ad oggetti consente di creare interfacce (ed estenderle) di modo che i sistemi non si debbano conoscere a vicenda, ma possano delegare le operazioni.

Chiedetevi come mai addirittura i software negli ultimi dieci anni (come WordPress, o gli editor com Eclipse/vi/emacs, o le suite come Microsoft Office) abbiano sviluppato il concetto di PlugIn: Acrobat Distiller è un plugin che estende Office, Eclipse addirittura è basato solo su enormi collezioni di plugin che lo estendono, ecc.

Questo si può fare anche in un’ottica funzionale, imitando però di fatto l’OOP:

Esempio1 nel linguaggio C,  sotto unix, le funzioni di gestione file accettano un intero chiamato file descriptor. Che cosa è se non un identificativo di un oggetto file, che poi internamente viene gestito dalla libreria del linguaggio C?

L’Ansi C esplicita questa cosa passando un puntatore ad una struttura FILE che ci deve rimanere ignota. Si tratta in pratica di un modello di programmazione funzionale molto simile a CLOS o python, in cui si hanno funzioni il cui primo parametro è sempre l’oggetto su cui si lavora!

A questo punto l’OOP può essere vista come un modo enormemente semplice di ottenere quanto visto sopra.

Infine, uno dei più grandi difetti dell’OOP è… l’ereditarietà. Benché il concetto sia utilissimo, essa in letteratura è stata usata anche per suggerire il riuso del codice. La conseguenza è che ogni tanto si può essere tentati di derivare una classe B da una classe A solo perché nella classe A ci sono dei metodi che… bhe… “fanno comodo”. Evitate questa tentazione. Isolate quei metodi, metteteli in un’ altra classe X, fate quello che volete ma non dite che B è un sottotipo di A solo perché hanno in comune il metodo di parsing degli interi :)