AIRT Lab - Università Politecnica delle Marche

Transcript

AIRT Lab - Università Politecnica delle Marche
Università Politecnica delle
Marche
Facoltà di Ingegneria
Ingegneria Informatica
PROGETTO DI UN MIDDLEWARE IN “RUBY ON
RAILS” PER LA TELEREFERTAZIONE MEDICA:
REALIZZAZIONE LATO CLIENT
Relatore
Candidato
Prof. Aldo Franco Dragoni
Alfredo Flauto
Matr. 1022956
Correlatore
Prof. Paolo Puliti
Anno Accademico 2007/2008
1
INDICE
1. INTRODUZIONE............................................................................................................4
1.1 Telemedicina...................................................................................................4
1.2 Stato dell’arte..................................................................................................6
1.3 Progetto “Miro on Rails”................................................................................8
1.4 Ruby e telemedicina.....................................................................................11
1.4.1“Ruby on Rails”....................................................................................14
1.5 Le immagini DICOM..................................................................................16
1.6 “Scrubbing” dei dati medici riservati..........................................................19
1.7 Miro on Rails e l’Open Source....................................................................21
2. ANALISI DEI REQUISITI............................................................................................23
2.1 Analisi orientata agli scenari........................................................................23
2.2 Schemi di Jacobson......................................................................................25
2.3 Requisiti della cartella clinica......................................................................34
2.3.1 Profilo del paziente..............................................................................35
2.3.2 L’anamnesi..........................................................................................36
3. PROGETTAZIONE.......................................................................................................40
3.1 Architettura...................................................................................................40
3.2 Classi di progettazione.................................................................................42
3.3 Progettazione cartella clinica........................................................................43
3.4 Confronto tra Ruby on Rails e tecnologie alternative..................................46
3.4.1 Rails.....................................................................................................52
4. IMPLEMENTAZIONE LATO CLIENT.......................................................................54
4.1 Realizzazione Database...............................................................................54
4.2 Ambiente di sviluppo e tecnologie software utilizzate................................57
4.2.1 Eclipse con plugin Aptana + RadRails + Ruby...................................57
4.2.2 SSH......................................................................................................60
4.2.3 Prototype..............................................................................................66
2
4.2.4 Ajax......................................................................................................67
4.2.5 Mantis bug tracker................................................................................69
4.2.6 Sistema operativo.................................................................................72
5. STRUTTURA MIRO ON RAILS..................................................................................75
5.1 Autenticazione.............................................................................................75
5.2 Administrator...............................................................................................77
5.3 Requester.....................................................................................................81
5.4 Doctor..........................................................................................................91
5.5 Sezione messaggi.........................................................................................95
6. CONCLUSIONI E SVILUPPI FUTURI.......................................................................98
6.1 Conclusioni...................................................................................................98
6.2 Sviluppi futuri...............................................................................................99
Appendice A: CONTROLLERS.......................................................................................101
Appendice B: MODELS....................................................................................................120
Bibliografia.........................................................................................................................126
3
1. INTRODUZIONE
1.1 Telemedicina
Il termine TELEMEDICINA si presta a svariate definizioni, non sempre univoche in
letteratura, che spesso focalizzano l’attenzione solo su alcuni aspetti della materia.
Si tratta sostanzialmente della trasmissione in tempo reale di informazioni a carattere
scientifico tra medico e cittadino o tra addetti ai lavori, attraverso sistemi di comunicazione
di tipo telematico/informatico.
La definizione più esaustiva del termine è senz’altro quella concordata a livello CEE da
una Commissione di esperti, che ha redatto un documento sulle prospettive di sviluppo
della telemedicina in Europa (Advanced Informatics in Medicine - AIM 1990) con
l’obiettivo di migliorare la qualità dei servizi sanitari, facilitare la formazione professionale
di medici e infermieri ed ottimizzare il trasferimento qualificato di dati ed esperienze tra i
vari Paesi europei. Secondo la Commissione Europea, organizzatrice tra l’altro dell’EHTO
(European Health Telematics Observatory – Osservatorio delle applicazioni mediche della
telematica), la telemedicina è “l’integrazione, monitoraggio e gestione dei pazienti,
nonché l’educazione dei pazienti e del personale, usando sistemi che consentano un pronto
accesso alla consulenza di esperti ed alle informazioni del paziente, indipendentemente da
dove il paziente o le informazioni risiedano”.
I campi di applicazione della telemedicina sono numerosissimi e in continua evoluzione,
dalla cardiologia (trasmissione di tracciati elettrocardiografici) alla radiologia (immagini
radiografiche e computerizzate), dalla dermatologia (foto digitali di lesioni cutanee)
all’anatomia patologica, dalla ginecologia (monitoraggio in gravidanza) all’odontoiatria e
via dicendo; praticamente ogni branca della medicina può avvalersi di questo strumento
per migliorare l’esercizio delle attività cliniche, assistenziali e didattiche.
Applicare la telematica in ambito medico significa, infatti, rispondere con tempestività alle
esigenze diagnostiche (telediagnosi) e terapeutiche (teleassistenza) di cittadini distanti
dalle strutture sanitarie o comunque impossibilitati a muoversi da casa; fornire una risposta
valida ed efficace in caso di malati cronici o anziani e un supporto indispensabile nelle
urgenze
(telesoccorso);
favorire
l’aggiornamento
scientifico
(teledidattica)
e
il
collegamento interattivo tra medici (videoteleconsulto) con condivisione dinamica di
4
informazioni, cartelle cliniche digitali, tracciati diagnostici, immagini biomediche, che si
“muovono” in tempo reale e con la massima definizione.
Ne consegue una concreta interrelazione tra le strutture minori o più deboli e quelle
maggiori o specialistiche.
Oltre ad avere utilità in campo strettamente clinico/didattico, la telemedicina può
contribuire all’ottimizzazione della gestione del sistema sanitario, mediante vaste
applicazioni di tipo amministrativo.
Attraverso la creazione di una rete telematica di strutture sanitarie è possibile, infatti,
ottenere informazioni sulla disponibilità dei posti letto, sull’accesso alle liste di
prenotazione, troppo spesso caratterizzate da ritardi esagerati, sulla gestione delle cartelle
cliniche, con gli adeguati accorgimenti per la tutela della privacy, dei referti medici etc.
Questo si traduce in un sensibile miglioramento sia della qualità dei servizi per il cittadino,
che si sente più garantito, sia delle condizioni di lavoro del personale, che accede più
facilmente alle informazioni. Non ultimo, nell’ottica di una congrua riorganizzazione del
Sistema Sanitario, l’utilizzo delle tecnologie informatiche, snellendo le procedure e
migliorando i servizi offerti, contribuisce a garantire anche un contenimento della spesa
sanitaria.
La nostra tesi ha riguardato un ambito ben specifico della telemedicina che può essere
riassunto dalle due parole chiave:
Telerefertazione
Second Opinion
Telerefertazione: nell'ambito della diagnostica clinica, è possibile per un medico effettuare
la diagnosi su un paziente che non è fisicamente nello stesso posto del medico, attraverso
la trasmissione a distanza di dati prodotti da strumenti diagnostici.
Second opinion medica: è una delle applicazioni più comuni nell'ambito della
telemedicina, essa consiste nel fornire una opinione clinica a distanza supportata da dati
acquisiti inviati ad un medico remoto che li analizza e li referta producendo di fatto una
seconda valutazione clinica su un paziente.
5
1.2 Stato dell’arte
Oggigiorno i sistemi sanitari mondiali stanno facendo passi da gigante nell’utilizzo
massiccio della telemedicina, grazie soprattutto allo sviluppo di nuove tecnologie. In
ambito nazionale ogni regione si sta attrezzando allo sviluppo di sistemi di informatica
medica.
Uno dei principali progetti a livello nazionale è rappresentato da As.ter: un sistema
informativo per la gestione di tutte le attività del territorio sviluppato dalla USL 11 di
Empoli. As.Ter integra, con l’ausilio di una piattaforma tecnologica innovativa, tutti gli
applicativi ed i database delle attività sanitarie e sociali svolte sul territorio, consentendo la
rilevazione dei bisogni complessivi dei cittadini, l’individuazione delle modalità e dei
tempi di risposta ai loro bisogni, la rilevazione dei costi; tutto ciò al fine di pianificare e
gestire le attività sociosanitarie sul territorio in un ottica manageriale di costi/benefici.
Un altro progetto è stato proposto dal servizio sanitario regionale Emilia-Romagna con il
nome di SOLE. Esso è finalizzato a realizzare una rete telematica, basata su una serie di
hub (centri di archiviazione) e spoke (centri di acquisizione), di collegamento tra i servizi
ospedalieri e i servizi territoriali per agevolare la comunicazione tra operatori sanitari e, di
conseguenza, agevolare l'erogazione dei servizi con importanti e positive ricadute sulla
continuità assistenziale e sulla semplificazione dell’accesso ai servizi per il cittadino.
Un’interessante applicazione sviluppata da un’equipe guidata da Ennio Amori, all’interno
di questo progetto è “Neurosurgery Teleconsulting”, un servizio di teleconsultazione tra i
centri di neurochirurgia collegati attraverso la rete hub&spoke, nella nuova logica
distribuita e digitale, in modo da poter trattare ogni trauma e lesione in modo appropriato
sfruttando il livello avanzato che ha raggiunto l’IT.
Molti sono i progetti pilota che puntano a creare tra i nostri ospedali e centri d’eccellenza
un collegamento con i paesi dell’Europa dell’est, che sono da poco entrati nella comunità
europea, per fornire servizi di teleconsulto e telediagnosi, come per esempio tra Padova o
Milano e la Romania. Nello sviluppo di questo tipo di progetti è possibile usufruire anche
dei finanziamenti della comunità europea che ovviamente danno maggiore spinta alla
ricerca e permettono di pagare la consulenza di software house, esterne alle aziende
sanitarie, che possono dare un forte supporto tecnico e far ottenere un prodotto software
più completo ed evoluto.
6
In tutto questo panorama di progetti non emerge nessun sistema simile a quello sviluppato
nella nostra tesi, infatti per gli esempi citati si tratta sempre di servizi ad hoc per
applicazioni specifiche, senza una vera ottica di integrazione e supporto globale di servizi
sanitari delocalizzati.
Un capitolo a parte merita il progetto MedTel, in quanto si propone di realizzare lo stesso
servizio di Miro on Rails ma con tecnologie differenti.
Il progetto MedTel (Medical Telereporting System) è stato realizzato grazie alla
collaborazione tra l’Università Politecnica delle Marche e L’ASUR Marche zona 7 di
Ancona e finalizzato alla sperimentazione della telerefertazione. In questo caso l’utilizzo
dei sistemi di comunicazione e informatici a favore del servizio sanitario, è stato incentrato
per favorire il servizio di refertazione verso le esigenze di tipo diagnostico, per paesi come
l’Africa che sono in via di sviluppo. Tramite l’utilizzo di questo sistema, si è in grado di
poter effettuare una refertazione delocalizzata, ossia poter effettuare un referto
indipendentemente dal posto e dal momento in cui è stato effettuato un determinato esame
clinico. Offre quindi un tipo di servizio asincrono. Gli esami svolti, e gli eventuali referti
medici allegati, verranno successivamente inseriti e registrati nella memoria del sistema,
che ne garantirà la sicurezza e privatezza.
7
1.3 Progetto “Miro on Rails”
Il termine “MiRo” è l’arcronimo per Medical Report e l’estensione “on Rails” è stata
aggiunta per evidenziare il framework utilizzato per la progettazione.
Il progetto Miro on Rails nasce dall’esigenza di poter delocalizzare la refertazione
diagnostica. Infatti l’obiettivo del nostro progetto è quello di realizzare un prodotto che
implementi un servizio di refertazione asincrono, in grado di separare l’effettuazione
dell’esame clinico dalla refertazione medica, da un punto di vista temporale ma anche
spaziale. Quindi per asincrono intendiamo che non ci si aspetta che l’esame venga refertato
in tempo reale, ma in un tempo accettabile concordato tra i fornitori del servizio e gli
utenti.
La parola chiave di Miro on Rails è “telerefertazione”: soluzione avanzata di telemedicina.
Il progetto rientra infatti nell’ambito applicativo della Telemedicina.
Le applicazioni di telemedicina possono essere utilizzate per sopperire ad eventuali
carenze di copertura territoriale dei servizi sanitari o nel caso di problematiche legate alle
difficoltà dei trasporti o all’impossibilità di facili spostamenti da parte dei cittadini
soprattutto se anziani senza assistenza.
Pensiamo poi alle popolazioni del terzo mondo, proprio queste popolazioni sono quelle che
più soffrono per la difficoltà di collegamenti, per la povertà, per la carenza di servizi
medici adeguati.
In questi contesti ambientali le possibilità che offre la telemedicina può limitare il disagio
puntando a portare il servizio alle persone; sfruttando le reti telematiche e la flessibilità
delle attrezzature informatiche si “avvicina” il servizio verso l’uomo e non viceversa.
Miro on Rails è pensato soprattutto per aiutare le popolazioni del terzo mondo, quindi
l’ambito di utilizzo è a livello mondiale.
Il sistema di telerefertazione che andremo a progettare si propone di muovere le
informazioni e non i pazienti (Figura 1).
Obiettivo specifico del progetto è la realizzazione di un Software sperimentale che offra un
servizio di telerefertazione medica: trasmissione di analisi mediche (tracciati ECG, ecc...) e
dei relativi referti in formato elettronico attraverso internet.
Il Sistema di Telerefertazione ipotizzato è un sistema di uso clinico composto da strumenti
di analisi mediche (per esempio elettrocardiografi), da computer connessi in rete, un’unità
8
centrale (“Server” di refertazione) dove vengono archiviati elettronicamente tutti i dati
anagrafici e clinici dei pazienti e tutti gli esami acquisiti dagli strumenti, tutto il sistema è
gestito dal software Miro on Rails.
Da uno dei PC, il Medico può esplorare e consultare tutti i dati memorizzati dal Sistema ed
effettuare la refertazione degli esami.
Il Sistema permette di controllare automaticamente tutto il flusso di lavoro di un esame
clinico. In questo modo non è più necessario spostare da una località all’atra la stampa su
carta dell’esame e la cartella clinica: attraverso internet le informazioni viaggiano in
formato elettronico fino al Medico specialista e tornano indietro al paziente corredate dalla
diagnosi.
L’esame può essere effettuato presso qualunque laboratorio in qualunque regione del
mondo e se necessario direttamente presso il domicilio del paziente (figura 2):
1. Un Requester tramite l’interfaccia di Miro on Rails inserisce i dati del paziente (i dati
anagrafici possono essere inseriti all’atto della prenotazione dell’esame) e le informazioni
sull’esame eseguito comprensivo dell’eventuale file di qualità diagnostica (per esempio
tracciato ECG), il SW memorizzerà tutti i dati sul database del server centrale.
2. Il medico specialista tramite le apposite dotazioni HW/SW, potrà consultare la cartella
clinica del paziente e l’evento per cui è richiesta un’opinione.
3. Eventualmente lo specialista provvederà alla stesura del referto in formato elettronico:
procede alla consultazione del file (esempio: ECG) di qualità diagnostica e provvede alla
stesura del referto tramite le funzionalità del SW.
4. La consultazione dei referti avviene direttamente dall’interfaccia del programma.
5. Eventualmente il Requester chiude l’evento.
Il vantaggio è che il referto sarà reso disponibile ai medici curanti via web tramite Miro on
Rails: sito dedicato, ad accesso riservato, consultabile in modo anonimo da qualsiasi PC
connesso ad Internet.
Sul sito appositamente costruito sarà ad esclusiva disposizione dagli utenti autorizzati la
cartella clinica del paziente con il referto rilasciato dal medico specialista firmato
digitalmente ed eventualmente accessibile in modalità anonima direttamente dal paziente
in caso di necessità.
9
Figura 1: Architettura generale
Figura 2: Flow Diagram
10
1.4 Ruby e telemedicina
Le caratteristiche che dovrebbe avere un ideale linguaggio di programmazione nel campo
della telemedicina sono:
9 Free
9 Open Source
9 Facile da scaricare da internet e da installare
9 Facile da imparare
9 Facile da “leggere”
9 Capace di rispondere ad ogni “Computational Task” dell’area di interesse del
programmatore
9 Veloce
9 “User Community” attiva
9 Disponibilità di numerose librerie per espandere le funzionalità del linguaggio
9 Linguaggio che supporti una prospettiva compatibile all’ambito telemedico
Occorre quindi valutare se Ruby ha tali caratteristiche. Dimostreremo che Ruby possiede le
proprietà che lo rendono adatto alla realizzazione di un sistema client-server per servizi
avanzati di telerefertazione medica.
Ruby è un linguaggio molto interessante per programmatori e non programmatori ed è free
e facile da installare. I programmatori si accorgeranno che Ruby permette loro di scrivere
applicazioni software (well-designed e object-oriented) in meno tempo, con meno codice e
con minore complessità rispetto ad altri linguaggi di programmazione. Quindi i non
programmatori che cercano il miglior linguaggio da imparare farebbero bene a scegliere
Ruby.
Fra i numerosi linguaggi di programmazione esistenti, cosa rende Ruby speciale?
Ruby è stato creato nel 1995 da Yukihiro Matsumoto, da allora ha avuto un enorme
successo in Giappone e nel resto del mondo. I programmatori Ruby hanno accesso alle
librerie Ruby dislocate nel mondo attraverso RubyGem, un sistema per scaricare e
installare software Ruby che si trova su server remoti. RubyForge è una repository e
risorsa di sviluppo per gruppi di programmatori che collaborano allo sviluppo di nuove
11
librerie di Ruby. Queste nuove librerie sono liberamente disponibili all’interno della
community di Ruby.
Il progetto Ruby più famoso è “Ruby on Rails”, un framework per applicazioni web
sviluppato in Ruby (vedi capitolo 1.6).
In generale se si sceglie Ruby, si avrà la possibilità di importare ed esportare dati RDF
(Resource description Framework) e YAML (Yet Another Metadata Language),
condividere immagini, creare Internet scripts client-server, accedere a databases,
incapsulare richieste per web services in messaggi SOAP, scrivere e-mail scripts e creare
applicazioni web.
I più comuni “computational tasks” in telemedicina sono:
¾ Estrarre sottoinsiemi di dati da uno o più database
¾ Creare ed organizzare un nuovo database
¾ Analizzare i dati contenuti in un database usando diverse strategie
¾ Indexing e autocoding di testi e datasets
¾ Trasformare datasets in formati standard
¾ Unire dati eterogenei in datasets utili
¾ De-identificare (“scrubbing”) datasets che contengono dati riservati
¾ Distribuire dati e servizi attraverso internet
¾ Descrizione dei dati in maniera logica, in modo da facilitare la condivisione dei
dati
Ruby è un linguaggio object-oriented, ogni cosa in Ruby è un oggetto. Ruby conosce il
tipo di ogni oggetto (per esempio, Array, Numeric, String e Class). Le classi sono oggetti
speciali perché contengono dati e metodi e possono creare un’unica istanza di loro stessi.
Le classi Ruby possono rappresentare il mondo naturale e adattarlo alla costruzione logica
dei moderni modelli di dati (come RDF). Si troverà che la programmazione Ruby fa
risparmiare tempo e aumenta la produttività.
Ruby è un linguaggio che fornisce vari livelli di programmazione:
¾ Livello 1: uso di strutture dati, iteratori e classi incorporate in Ruby
12
¾ Livello 2: uso di estensioni che provengono dalla installazione standard di Ruby,
incluse le librerie standard e Ruby GEMS. Programmare facendo uso di tecniche di
computational reflection
¾ Livello 3: gli utenti creano la propria classe di librerie. I programmatori usano
RDoc per preparare una classe di librerie ben documentate
¾ Livello 4: creare applicazioni web con Ruby on Rails, CGI o protocolli Network
¾ Livello 5: usare tecniche avanzate class-oriented come delegazione e polimorfismo,
sviluppare interfacce grafiche utente e usare tecniche di programmazione come
error trapping e unit testing
¾ Livello 6: estendere e incorporare Ruby con altri linguaggi di programmazione
¾ Livello 7: preparare applicazioni software commercial-grade
Di norma si tende ad associare la programmazione object-oriented ai tre concetti di:
ereditarietà, polimorfismo e incapsulamento. In Ruby c’è una quarta proprietà:
composition. La composition (anche chiamata layering e aggregation) è una tecnica dei
linguaggi di programmazione object-oriented nella quale le classi sono provviste di metodi
che non sono essenziali per la classe (cioè, la loro esclusione dalla classe non dovrebbe
cambiare il nostro concetto degli oggetti contenuti nella classe). In Ruby, Mixins è una
semplice e potente tecnica di programmazione composizionale così come la delegazione.
La delegazione è una particolare tecnica che crea un oggetto “ombra” in una seconda
classe.
Ruby è distribuito con una varietà di programmi chiamati estensioni. Le estensioni sono
programmi Ruby che sono estesi dall’inclusione di altre risorse, in particolare routines C.
Le estensioni Ruby saranno supportate solo se il sistema operativo ha accesso alle risorse
chiamate dalle estensioni.
Il vantaggio della Libreria Standard Ruby è quello di avere le stesse librerie incluse
nell’istallazione per chiunque utilizza Ruby.
Le GEMS sono programmi Ruby a cui si può accedere attraverso internet. Dopo aver
installato Ruby e verificato che il nostro computer è collegato ad internet, si può utilizzare
il programma GEM per installare le gems. Una delle più importanti Ruby gems è Ruby on
Rails.
13
1.4.1 “Ruby on Rails”
Ruby on Rails è un ambiente di lavoro, un framework che semplifica lo sviluppo, l’utilizzo
e la gestione delle applicazioni web.
Ovviamente, tutti gli ambienti web sostengono di avere queste caratteristiche. Dunque, che
cosa rende differente Rails? E’ possibile rispondere a questa domanda esaminandola da
diversi punti di vista. Uno di questi è l’analisi dell’architettura. Nel corso degli anni, per i
progetti web più impegnativi la maggior parte degli sviluppatori ha scelto di utilizzare
un’architettura di tipo MVC (Modello-Vista-Controller) in quanto, secondo molti
programmatori, consente di strutturare le applicazioni in modo più lineare. I framework
Java come Tapestry e Struts si basano su MVC, come Rails, del resto. Quando si sviluppa
in Rails, ogni porzione di codice ha la sua collocazione, e tutti i componenti
dell’applicazione interagiscono in modo standard. Si potrebbe affermare che è come se si
iniziasse con lo scheletro di un’applicazione già pronto.
Un altro punto di vista consiste nell’osservazione del linguaggio di programmazione. Le
applicazioni Rails sono scritte in Ruby, un moderno linguaggio di scripting orientato agli
oggetti. Ruby è conciso, pur senza essere incomprensibilmente stringato: il codice Ruby
consente di esprimere le idee in modo naturale e chiaro. Per questa ragione, i programmi
possono essere scritti più facilmente e, considerazione non meno importante, letti anche a
distanza di mesi. Inoltre, Ruby si presta a uno stile di programmazione che semplifica la
creazione di metodi che agiscono quasi come estensioni sintattiche. Alcuni esperti
definiscono questa tecnologia con il termine metaprogrammazione: grazie a essa, non
soltanto i programmi risultano più brevi e leggibili, ma è possibile far eseguire
direttamente nel codice di base attività che di norma richiederebbero l'impiego di file di
configurazione esterni, tecnica che facilita l’analisi di quanto avviene all’interno del
programma. Il codice seguente definisce la classe modello di un progetto: si consideri la
quantità di informazioni che possono essere espresse in poche righe di codice.
class Project < ActiveRecord::Base
belongs_to :portfolio
has_one :project_manager
has_many :milestones
has_and_belongs_to_many :categories
validates_presence_of :name, :description
validates_acceptance_of :non_disclosure_agreement
validates_uniqueness_of :key
end
14
Il terzo punto di vista è quello filosofico. La progettazione di Rails è stata governata da due
concetti chiave: DRY (Don’t repeat Yourself, non ripetetevi) e convention-overconfiguration. DRY significa che ogni elemento di informazione nell’ambito di un sistema
dovrebbe essere espresso in un solo punto e, per adattarsi a questo principio, Rails utilizza
la potenza di Ruby. Difficilmente si trovano duplicazioni in un’applicazione Rails: si dice
quello che occorre soltanto una volta, in un punto del codice spesso ispirato alle
convenzioni dell’architettura MVC, quindi si procede oltre.
Anche convention-over-configuration è un concetto essenziale, e indica che Rails offre
soluzioni predefinite per quasi tutti gli aspetti che compongono un’applicazione.
Attenendosi alle convenzioni, si riesce a realizzare un’applicazione Rails con meno codice
di quello che occorre per la configurazione XML di una tipica applicazione web Java, ma
Rails può essere utile persino per infrangere le convenzioni, perché semplifica anche
questo compito.
Si potrebbe accennare anche a tutte le interessanti funzionalità di Rails, tra e quali il
supporto integrato ai servizi web, il ricevimento della posta elettronica, AJAX (per
applicazioni web altamente interattive), l’ambiente completo per test unitari (unit testing).
15
1.5 Le immagini DICOM
Esistono probabilmente centinaia di formati di file immagine. Usando Ruby è possibile
manipolare più di 90 tipi di file immagine con RMagick e ImageMagick.
RMagick e ImageMagick non fanno parte del pacchetto di distribuzione standard di Ruby
ma possono essere ottenuti da RubyForge.
Generalmente il formato più utilizzato nel web è il JPEG (joint photographic experts
group), le immagini che usano questo formato possono essere visualizzate dai web bowsers
più popolari.
La possibilità di scambiare immagini mediche corredate da varie informazioni attraverso
reti telematiche, ha richiesto la creazione di uno standard di comunicazione globale, tale da
garantire l’intercomunicabilità tra sistemi eterogenei. DICOM (acronimo di Digital
Imaging
and
Communication
in
Medicine)
rappresenta
un
modello
di
tale
standardizzazione, la cui nascita è stata però inizialmente ostacolata dalla pluralità di
prodotti hardware in campo medico, i quali, proponendo standard proprietari avevano
creato una situazione di completa incomunicabilità tra apparecchi di case costruttrici
differenti. Sviluppato per la gestione di immagini digitali prodotte da diverse modalità
radilogiche (TC,RM, Ecografia, Angiografia digitale, Fluoroscopia digitale, etc.) e la loro
trasmissione su reti standard, garantisce l’intercomunicabilità tra sistemi eterogenei.
A tal proposito un progetto open source molto interessante è Osiris, un lettore DICOM
multipiattaforma che consente di fare numerose operazioni sulle immagini.
Figura 3: caratteristiche del file
16
Figura 4: file associato al paziente
Figura 5: esempio immagine DICOM
17
Il software permette di:
• Aprire e visualizzare qualsiasi immagine DICOM con le relative caratteristiche
(Figura 3 e 5)
• Convertire il formato di qualsiasi file.DICOM nei principali formati immagine
(TIFF, BITMAP, ecc) e viceversa
• Mantenere una lista di pazienti anonimi a cui associare i file diagnostici (figura 4)
• Eseguire le operazioni base dei normali visualizzatori di immagini
18
1.6 “Scrubbing” dei dati medici riservati
Oggi una delle sfide più importanti in telemedicina è la sicurezza e la privacy dei dati
trattati. Poiché i dati medici sono spesso estratti da archivi protetti, coloro che lavorano con
questi dati devono essere a conoscenza della legislatura sulla protezione dei dati medici.
Negli Stati Uniti, i dati medici privati sono protetti da due regolamenti federali: HIPAA
(Health Insurance Portability and Accountability Act) e Common Rule.
L’HIPAA, per esempio, elenca 18 identificatori che devono essere assenti da qualunque
archivio medico de-identificato:
9 Nomi
9 Suddivisione geografica più piccola di uno stato
9 Date (eccetto l’anno) direttamente collegate al paziente
9 Numeri di telefono
9 Numeri di fax
9 Indirizzi e-mail
9 Numeri di previdenza sociale
9 Numeri di cartelle mediche
9 Numeri beneficiari piani previdenziali
9 Numeri di conto
9 Numeri di certificati e licenze
9 Identificatori e numeri di serie di veicoli
9 Identificatori e numeri di serie di dispositivi elettronici
9 Web URLs
9 Indirizzi IP
9 Identificatori biometrici
9 Immagine fotografica del paziente
9 Ogni altro numero identificativo univoco, eccetto quelli permessi da HIPPA per riidentificare i dati
L’HIPAA e Common Rule permettono l’uso di dati medici riservati quando il paziente è
informato dei rischi e fornisce il consenso al trattamento. In Italia i dati sensibili come
quelli medici sono protetti da una normativa: Il Codice in materia di protezione dei dati
19
personali. Una particolare attenzione richiede l’Autorizzazione n. 2/2008 al trattamento
dei dati idonei a rivelare lo stato di salute e la vita sessuale - 19 giugno 2008.
Nei processi di automazione della sanità pubblica devono rientrare anche le regole previste
per la protezione dei dati personali, lo ha ricordato Gaetano Rasi, componente dell'Autorità
Garante
per
la
protezione
dei
dati
personali,
nel
corso
di
un
convegno.
Rasi ha sottolineato come le applicazioni di telemedicina sono in rapido aumento e in Italia
ormai il 40 per cento delle strutture mediche si avvale del teleconsulto e il 25 per cento
dispone di soluzioni di home care. Si tratta quindi di nuove opportunità di collegamento
virtuoso tra paziente e strutture sanitarie e via via sono messi a disposizione servizi di
informazione assai rilevanti come disponibilità di posti letto, accesso alle liste di
prenotazione, gestione delle cartelle cliniche e via dicendo.
Questi importanti sviluppi, ha spiegato Rasi, non devono però far dimenticare come i dati
personali e in particolare quelli sensibili, vale a dire le informazioni più riservate ed intime
della persona, devono essere trattati nella massima riservatezza e nel rispetto della dignità
della persona "Anche l’outsourcing e il telelavoro - ha osservato Rasi - sono realtà in
espansione e contribuiscono alla profittabilità del business e all’efficienza delle pubbliche
prestazioni. Il 43% dei contratti di outsourcing copre, ad esempio, l’area dell’Information
technology, il 25% quella delle risorse umane. In quest’ultimo caso vengono affidati a
partner esterni non solo l’amministrazione, ma anche, per esempio, la gestione del percorso
di carriera dei dipendenti".
"L’euforia informatica - ha invece sottolineato il segretario generale dell'Autorità Giovanni
Buttarelli - non deve far dimenticare che Costituzione Europea e Codice della Privacy
mettono in primo piano il diritto della persona a verificare come vengono trattati i propri
dati personali. Siamo forse primi nel mondo per il quadro giuridico sull’informatica e la
telematica. Il Testo Unico sulla privacy è pronto per rispondere alle questioni poste dalla
telemedicina, che recherà grossi vantaggi, come la possibilità di accedere con una
password alla propria cartella clinica da qualunque parte del mondo, ma causerà anche
nuovi rischi relativi, ad esempio, alla dispersione di informazioni. L’informativa al
cittadino dovrà tenere conto di tutti questi aspetti.
"Sulle nuove autostrade del sole del trattamento dei dati - ha concluso Buttarelli - il
cittadino avrà sempre il diritto di intervenire sul trattamento dei propri dati".
20
1.7 Miro On Rails e l’Open Source
Alcuni dei vantaggi delle soluzioni Open Source rispetto ai software proprietari sono:
•
Ha un basso TCO: il Total Cost of Ownership (TCO) è uno dei parametri per
valutare il costo di un prodotto. Partendo dal modello di costo del prodotto, si
identificano la varie voci di costo e si stimano. Non bisogna dimenticare tutte
quello voci di costo "nascoste", come per il supporto tecnico, l'amministrazione del
sistema, l'upgrade.
•
Non lega al fornitore: la possibilità di non essere legati ad uno specifico fornitore di
software, libera il privato, ed ancora più l'azienda da eventuali politiche
"protezionistiche" del fornitore
• Innovazione e potenziale per l'evoluzione sono generalmente agevolati
•
Avendo una comunità di persone che controlla ed ottimizza il software, si ottiene
un prodotto molto efficiente
• Flessibilità: la possibilità di personalizzare ogni aspetto di un programma, aumenta
la flessibilità del sistema complessivo. Aumenta così anche il range di possibilità
applicative di un programma. Avendo il codice a disposizione si può "portare"
un'applicazione su una nuova architettura, aprendo così nuove possibilità.
Uno dei temi fondamentali nel campo della telemedicina e dell’informatica medica è
cercare di ottimizzare la gestione sanitaria per garantire un considerevole abbassamento dei
livelli della spesa e rendendo più efficienti, nel contempo, le prestazioni di qualità del
servizio a tutto vantaggio della salute dei pazienti.
Da un lato c'è il bisogno di far convergere tutte le informazioni, soprattutto quelle che
concernono il singolo paziente, in una repository accessibile e condivisa dagli operatori
sanitari, e dall'altro di realizzare questa razionalizzazione senza aumentare il livello di
spesa:
l'idea alla base del progetto Miro on Rails è stata allora quella di sfruttare
al massimo la risorsa dell’Open Source
21
Lo sviluppo di Miro on Rails presenta come peculiarità delle scelte implementative la
preoccupazione di non legare la soluzione proposta all'utilizzo di un particolare assetto
informatico (tipologia di hardware, sistemi operativi, etc.), ma ,sfruttando l'approccio dei
sistemi Open Source, assicurare quella flessibilità necessaria a promuovere una vasta
adozione dei sistemi informativi e di comunicazione nel settore della Sanità.
Il Sistema Sanitario si sta avviando verso nuove frontiere di riorganizzazione e di
convergenza delle informazioni. Miro on Rails cerca di soddisfare proprio questa esigenza
ponendosi come obiettivo fondamentale quello di realizzare una “Virtual Health-Care
Agency”.
22
2. ANALISI DEI REQUISITI
2.1 Analisi orientata agli scenari
Un analisi di questo tipo serve per modellare i requisiti del sistema dal punto di vista
dell’utente. In tal senso il diagramma dei casi d’uso rappresenta un aiuto per definire che
cosa esiste al di fuori del sistema (attori) e che cosa dovrebbe essere fatto dal sistema (casi
d’uso).
Gli attori del sistema sono tre: Administrator, Requester, Doctor; ognuno avrà uno
specifico diagramma dei casi d’uso.
Figura 6: diagramma dei casi d’uso Administrator
23
Figura 7: diagramma dei casi d’uso Requester
Figura 8: diagramma dei casi d’uso Doctor
24
2.2 Schemi di Jacobson
1) SPECIFICA DI CASO D’USO: Autenticazione
ATTORI: Administrator, Requester, Doctor
BREVE DESCRIZIONE:
Ogni utente per poter accedere al sistema deve autenticarsi immettendo username e password
FLUSSO BASE:
• l’utente accede alla pagina di login di Miro on Rails tramite internet
• l’utente inserisce username e password
• l’utente attende la risposta del sistema
PRECONDIZIONI: l’utente deve essere registrato da un Administrator
POSTCONDIZIONI: autenticazione riuscita
ECCEZIONI: “Invalid user/password combination”
FREQUENZA DI UTILIZZO: Alta
CRITICITA’: Bassa
2) SPECIFICA DI CASO D’USO: Inserimento New User
ATTORI: Administrator
BREVE DESCRIZIONE:
L’administrator può registrare le informazioni di un nuovo utente e scegliere lo “User type”
(Administrator, Requester, Doctor)
FLUSSO BASE:
• l’administrator si autentica
• inserisce tutti i dati del nuovo utente
• salva la procedura
PRECONDIZIONI: il nuovo utente deve fornire alcuni dati obbligatori (name, surname,
username, mail, password)
POSTCONDIZIONI: “registration complete”
ECCEZIONI:
•
•
“Username has already been taken”
“obbligatory field!”
FREQUENZA DI UTILIZZO: Alta
CRITICITA’: Alta
25
3) SPECIFICA DI CASO D’USO: Visualizza Last Users
ATTORI: Administrator
BREVE DESCRIZIONE:
L’administrator può visualizzare gli ultimi users registrati
FLUSSO BASE:
• l’administrator si autentica
• visualizza gli ultimi users inseriti
FREQUENZA DI UTILIZZO: Bassa
CRITICITA’: Bassa
4) SPECIFICA DI CASO D’USO: Cancellazione User
ATTORI: Administrator
BREVE DESCRIZIONE:
L’administrator può cancellare dal sistema gli users del tipo Requester e Doctor
FLUSSO BASE:
• l’administrator si autentica
• seleziona uno user
• procede alla cancellazione
PRECONDIZIONI: selezionare uno o più users
POSTCONDIZIONI: cancellazione avvenuta
FREQUENZA DI UTILIZZO: Bassa
CRITICITA’: Bassa
5) SPECIFICA DI CASO D’USO: Visualizza Last Patients
ATTORI: Administrator
BREVE DESCRIZIONE:
Il requester può visualizzare gli ultimi pazienti inseriti
FLUSSO BASE:
• il requester visualizza l’elenco degli ultimi pazienti inseriti
FREQUENZA DI UTILIZZO: Alta
CRITICITA’: Bassa
26
6) SPECIFICA DI CASO D’USO: Add New Patient
ATTORI: Requester
BREVE DESCRIZIONE:
Il requester può inserire il profilo di un nuovo paziente
FLUSSO BASE:
• Il requester inserisce i dati del paziente
• salva la procedura
PRECONDIZIONI: “patient not found”
POSTCONDIZIONI: “registration complete”
ECCEZIONI:
•
•
il paziente già esiste
“obbligatory field!”
FREQUENZA DI UTILIZZO: Alta
CRITICITA’: Bassa
7) SPECIFICA DI CASO D’USO: Visualizza Last Clinical Problem
ATTORI: Requester
BREVE DESCRIZIONE:
Il requester può visualizzare gli ultimi clinical problems
FLUSSO BASE:
• Il requester visualizza gli ultimi clinical problems aperti o di cui si richiede una
second opinion
FREQUENZA DI UTILIZZO: Alta
CRITICITA’: Alta
27
8) SPECIFICA DI CASO D’USO: Visualizza Clinical Folder
ATTORI: Requester
BREVE DESCRIZIONE:
Il requester può visualizzare e gestire la clinical folder di un paziente
FLUSSO BASE:
• Il requester registra un nuovo paziente
• Visualizza la clinical folder
• Gestisce la clinical folder
PRECONDIZIONI: il paziente deve essere registrato
POSTCONDIZIONI: gestione clinical folder
FREQUENZA DI UTILIZZO: Alta
CRITICITA’: Alta
9) SPECIFICA DI CASO D’USO: Inserimento e modifica dati paziente
ATTORI: Requester
BREVE DESCRIZIONE:
Il requester può inserire i dati di un paziente e successivamente modificare il profilo dei
pazienti
FLUSSO BASE:
• Inserisci dati
• Modifica dati
• Salva dati o modifiche
PRECONDIZIONI: il paziente deve essere registrato
POSTCONDIZIONI: modifiche salvate
FREQUENZA DI UTILIZZO: Alta
CRITICITA’: Alta
28
10) SPECIFICA DI CASO D’USO: Add clinical problem
ATTORI: Requester
BREVE DESCRIZIONE:
Il requester può aprire un clinical problem nella cartella clinica di un paziente
FLUSSO BASE:
• Compilare la scheda con le informazioni dell’esame clinico
• Allegare eventuali file diagnostici
• Salvare la procedura
PRECONDIZIONI: aprire la cartella clinica del paziente
POSTCONDIZIONI: clinical problem aggiunto alla lista
ECCEZIONI: “Exam can't be blank”
FREQUENZA DI UTILIZZO: Alta
CRITICITA’: Alta
11) SPECIFICA DI CASO D’USO: Visualizza Report
ATTORI: Requester
BREVE DESCRIZIONE:
Il requester può visualizzare i reports emessi dai doctors
FLUSSO BASE:
• Selezionare un paziente
• Selezionare un clinical problem
• Visualizzare uno o più report
PRECONDIZIONI: selezionare un clinical problem
POSTCONDIZIONI: lettura referto medico
FREQUENZA DI UTILIZZO: Alta
CRITICITA’: Alta
29
12) SPECIFICA DI CASO D’USO: Close clinical problem
ATTORI: Requester
BREVE DESCRIZIONE:
Il requester può cambiare lo stato di un clinical problem a “close” nel caso sia soddisfatto del
referto medico
FLUSSO BASE:
• Selezionare un paziente
• Selezionare un clinical problem
• Cambiare lo stato a “close”
PRECONDIZIONI: aprire la cartella clinica del paziente
POSTCONDIZIONI: stato clinical problem aggiornato
FREQUENZA DI UTILIZZO: Alta
CRITICITA’: Alta
13) SPECIFICA DI CASO D’USO: Request second opinion
ATTORI: Requester
BREVE DESCRIZIONE:
Il requester può cambiare lo stato di un clinical problem a “request another” nel caso voglia
una second opinion
FLUSSO BASE:
• Selezionare un paziente
• Selezionare un clinical problem
• Cambiare lo stato a “request another”
PRECONDIZIONI: aprire la cartella clinica del paziente
POSTCONDIZIONI: stato clinical problem aggiornato
FREQUENZA DI UTILIZZO: Alta
CRITICITA’: Alta
30
14) SPECIFICA DI CASO D’USO: Visualizza clinical problems
ATTORI: Doctor
BREVE DESCRIZIONE:
Il Doctor può visualizzare i clinical problem di uno o più pazienti in base alla propria
specializzazione
FLUSSO BASE:
• Selezionare “clinical problems”
PRECONDIZIONI: i doctors possono visualizzare solo i clinical problems che riguardano la
propria specializzazione medica
POSTCONDIZIONI: scegliere un clinical problem
FREQUENZA DI UTILIZZO: Alta
CRITICITA’: Bassa
15) SPECIFICA DI CASO D’USO: Visualizza last messages
ATTORI: Doctor
BREVE DESCRIZIONE:
Il Doctor può visualizzare i messaggi lasciati da altri colleghi su determinati clinical problems
FLUSSO BASE:
• Selezionare “last topics”
• Selezionare il clinical problem di interesse
• Consultare il message
PRECONDIZIONI: selezionare “last topics”
POSTCONDIZIONI: visualizza message
FREQUENZA DI UTILIZZO: Alta
CRITICITA’: Bassa
31
16) SPECIFICA DI CASO D’USO: Add message
ATTORI: Doctor
BREVE DESCRIZIONE:
I doctors possono usufruire di un servizio di messaggistica con cui scambiarsi opinioni
FLUSSO BASE:
• Selezionare “add message”
• Scrivere il message
• Salvare la procedura
PRECONDIZIONI: selezionare un clinical problem
POSTCONDIZIONI: message aggiunto alla lista
ECCEZIONI: “message not inserted”
FREQUENZA DI UTILIZZO: Alta
CRITICITA’: Bassa
17) SPECIFICA DI CASO D’USO: Add report
ATTORI: Doctor
BREVE DESCRIZIONE:
I doctor possono emettere reports su clinical problem che riguardano la loro specializzazione
FLUSSO BASE:
• Selezionare “add report”
• Scrivere il report
• Salvare la procedura
PRECONDIZIONI: selezionare un clinical problem
POSTCONDIZIONI: report aggiunto
ECCEZIONI: “report not inserted”
FREQUENZA DI UTILIZZO: Alta
CRITICITA’: Alta
32
18) SPECIFICA DI CASO D’USO: Consultation clinical problem
ATTORI: Doctor
BREVE DESCRIZIONE:
Il doctor può consultare un clinical problem selezionandolo da una lista di eventi
FLUSSO BASE:
• Selezionare un clinical problem
• Consultare l’esame clinico
• Fare il download di eventuali allegati
PRECONDIZIONI: selezionare “clinical problems”
POSTCONDIZIONI: visualizzare “consultation”
FREQUENZA DI UTILIZZO: Alta
CRITICITA’: Alta
33
2.3 Requisiti della cartella clinica
La cartella clinica è la figura centrale del sistema Miro on Rails. Essa contiene tutte le
informazioni relative al paziente ed in più rappresenta il “luogo” in cui avviene lo scambio
di informazioni tra dottore e requester. Infatti la cartella clinica non è altro che la soluzione
grafica di tutti i dati relativi al paziente presenti nel database centrale:
tutti gli eventi e le informazioni vengono salvati in questo database e visualizzati tramite
opportune interfacce agli utenti, siano essi appartenenti alla categoria doctor o requester.
Una cosa importante da dire è che ovviamente la cartella clinica sarà presentata allo stesso
modo sia per il dottore che per il requester, con l’unica importante differenza che
quest’ultimo è l’unico che può inserire e manipolare i dati. Solo la figura del requester
gestisce il paziente e quindi è a contatto diretto con lo stesso.
La creazione della cartella clinica è un passo molto importante. Le caratteristiche che
infatti doveva avere la nostra cartella clinica sono le seguenti: avere a disposizione i dati
anamnestici del paziente, fornire con una certa rapidità le informazioni desiderate, essere
flessibile e duratura nel tempo.
Innanzitutto bisogna dire che in ambito medico esistono due tipi di cartelle cliniche, quella
utilizzata in medicina generale e quella utilizzata in ambito ospedaliero. In ospedale sarà
necessario focalizzare l’attenzione sugli eventi prossimi che portano un certo iter
diagnostico verso una determinata patologia. In medicina generale invece deve essere
utilizzata una cartella clinica orientata ai problemi, in cui tutti i dati ruotino attorno al
problema per cui è richiesta la visita. Si distinguono quindi tra problemi attivi, cioè quei
problemi che non hanno ancora trovato soluzione, e problemi inattivi, i quali sono già stati
risolti. La nostra cartella clinica contiene i dati di base generici del paziente, dalle allergie
ai problemi familiari; una lista dei problemi sia attivi che inattivi; un “diario clinico” del
paziente che comprende i dati oggettivi quali la pressione, il polso e simili, e dati soggettivi
come i sintomi manifestati.
Tutto questo è corredato dalla possibilità di visualizzare un eventuale esame di laboratorio,
dapprima digitalizzato e memorizzato dalla struttura che gestisce il paziente. Un’ultima
osservazione sulla costituzione della cartella clinica va fatta riguardo alla terminologia
utilizzata. Infatti nell’inserimento dei dati sarebbe meglio utilizzare una terminologia
34
universale, atta soprattutto a non creare possibili diversità di interpretazione tra i vari
medici, cosa molto importante nel campo della telemedicina.
2.3.1 Profilo del paziente
Passiamo ora ad analizzare la struttura vera e propria della cartella clinica. Inizialmente è
presente il profilo del paziente con tutti i dati anagrafici.
Il profilo diventa utile sia per il requester che deve ricercare un paziente nel database che
per il dottore che vuole conoscere la provenienza come fattore da considerare in una
diagnosi. I dati presenti nel profilo sono:
9 data e città di nascita
9 informazioni generali sulla residenza attuale
9 la struttura in cui è ospitato
9 altre informazioni generali quali il sesso, il grado di istruzione, lo stato civile e la
professione svolta
9 informazioni per contattare direttamente il paziente come il numero di telefono e
l’e-mail
Inoltre è stata anche implementata la possibilità di mantenere in archivio le informazioni
di pazienti deceduti, perciò come dato verrà anche fornita l’eventuale data di decesso.
Questo è stato fatto per il semplice motivo di avere una più ampia visione d’insieme della
situazione locale: si pensi che, per esempio, in caso di un’epidemia è utile sapere il tempo
in cui si trasmette e dopo quanto avviene l’eventuale decesso. I dati utili per contattare il
paziente direttamente sono stati inseriti per essere utilizzati come “rubrica” da parte del
requester e far aumentare la comunicazione e quindi la qualità del servizio offerto.
E’ importante ricordare che gli stessi dati sono visibili sia dal requester che dal dottore, tali
dati non dovrebbero però essere utilizzati dal dottore per contattare direttamente il paziente
tranne che per emergenza. Non devono essere quindi utilizzati per scavalcare la figura del
requester che deve fare da tramite tra il sistema e il paziente. Infatti il paziente non ha
conoscenze mediche adatte a fornire alcune generalità mediche, quindi, se si sfruttassero
tali dati per creare un legame diretto dottore-paziente, si rischierebbe di cadere in situazioni
non più gestibili.
35
2.3.2 L’anamnesi
Successivamente è presente la sezione riguardante l’anamnesi del paziente. Presenta varie
sottocategorie che rendono tutto più immediato e allo stesso danno una visione completa e
dettagliata delle informazioni relative al paziente.
La sezione anamnesi è stata creata con l’intento di avere sempre tutte le informazioni a
portata del doctor: tutte le informazione rimangono in primo piano e quindi sempre visibili.
Abbiamo deciso di operare con questo genere di struttura per dare un’ampia e completa
visuale del paziente, cosicché al primo impatto il dottore può avere già un’idea generale
sulla situazione medica.
Le sezioni di seguito sono identiche dal punto di vista del doctor e del requester, a tal
proposito bisogna ricordare che tutte le informazioni sono inserite dal requester, tramite
un’apposita form di inserimento, e recepite dal dottore.
Allergie
La prima sottosezione che si incontra è quella relativa alle allergie del paziente. La prima
scheda riassuntiva fornisce informazioni sul tipo di allergie salvate nella struttura dati e
relative a quel paziente. Quando si entra nel dettaglio vengono fornite informazioni
specifiche come la data di inizio dell’allergia e l’eventuale data di fine se questa non è più
diagnosticata. Sono inoltre presenti delle note generiche sull’allergia riscontrata utili per
una migliore diagnosi e lettura della cartella clinica.
Informazioni generali sulla famiglia
La sottosezione successiva è quella che comprende i dati della famiglia. Le informazioni
qui presenti riguardano il padre e la madre del paziente. Qui non è presente come nella
scheda precedente una parte riassuntiva, in quanto i dati sono univoci e al più potranno
essere modificati nel tempo. Dal punto di vista del dottore vengono visualizzate le seguenti
informazioni: viene reso noto se sono ancora vivi i genitori e qual è il loro gruppo
sanguigno. Naturalmente anche qui viene data la possibilità a chi gestisce il paziente di
inserire delle note aggiuntive riguardanti la famiglia, ovviamente inerenti allo stato clinico
e mirate ad ottenere una migliore diagnosi.
36
Patologie familiari
Nella prossima sottosezione vengono invece presentate le informazioni sulle patologie di
tutta la famiglia, cioè quegli individui con legami di sangue con il paziente. È qui presente
una scheda riassuntiva delle patologie che i familiari hanno avuto. E’ anche presente un
elenco di quali siano stati i membri della famiglia ad avere avuto quella specifica
patologia. Questa sottosezione è molto importante soprattutto per stabilire se ci siano
possibilità di malattie genetiche e quindi ereditabili dal paziente, o comunque connessioni
di carattere ambientale in cui vive il paziente.
Patologie del paziente
Nella sottosezione successiva invece si ha un resoconto completo e dettagliato delle
patologie che ha riscontrato precedentemente il paziente. Anche qui, come nelle patologie
familiari, è presente il riassunto che fornisce quali patologie sono state riscontrate nel
paziente. Se si entra nel dettaglio, oltre alla patologia, come informazioni utili vengono
fornite l’età a cui è stata diagnosticata e, nel caso che ce ne sia stato bisogno, il dettaglio
del ricovero in ospedale. Infatti vengono forniti i dati del ricovero ospedaliero, viene resa
nota la data di entrata e quella di uscita dall’ospedale, nonché informazioni su
quest’ultimo. Saranno presenti inoltre la diagnosi ricevuta dal paziente e le note con cui è
stato dimesso, per poter confrontarle con una eventuale nuova diagnosi. In questa
sottosezione comunque non devono essere inserite esclusivamente le patologie che hanno
causato una permanenza in ospedale, ma tutte quelle che il paziente ha avuto nell’arco
della sua vita.
Problemi fisiologici
Nell’ultima sottosezione dell’anamnesi sono presenti informazioni mediche generali
riguardanti il paziente. Infatti, vengono visualizzate qui le note riguardo i problemi
fisiologici del paziente quali la digestione o il sonno, ma anche informazioni che
riguardano il gruppo sanguigno del paziente e quello dell’eventuale partner, con la
possibilità di note aggiuntive. Ogni nota dovrebbe inquadrare subito il problema e fornire
anche più dettagli possibili, si deve ricordare che il dottore non è a contatto diretto e quindi
non può visitare di persona il paziente.
Problemi clinici del paziente
37
Ora passiamo all’ultima parte di cui è composta la cartella clinica e che rappresenta anche
il vero punto di scambio tra requester e doctor. In questa sezione è presente un elenco di
tutti i problemi clinici del paziente, con l’aggiunta di informazioni come la data, il numero
di esami svolti su ognuno, il numero di report e ovviamente lo stato di ogni evento.
Bisogna ora differenziare il discorso tra doctor e requester, prima di iniziare a spiegare tali
opzioni è utile però ricordare che il doctor può osservare tutti gli esami svolti ma può
refertare solo i problemi riguardanti la sua specializzazione. Come prima cosa il doctor
deve selezionare l’esame svolto che vuole refertare o comunque controllare, infatti è
possibile che siano stati fatti differenti esami per lo stesso problema clinico. I dati che
emergono da tale selezione sono quelli relativi al paziente quali peso, altezza, informazioni
sulla pressione sanguigna, sulla frequenza cardiaca, l’indice di massa corporea e infine
delle conclusioni generali. Successivamente può inserire un nuovo messaggio con cui
magari può richiedere ulteriori informazioni in merito all’esame svolto; scaricare sul
proprio computer l’esame digitalizzato; refertare l’esame selezionato compilando una form
apposito. Questa form, uguale sia per l’inserimento dei referti che dei messaggi, permette
di inserire informazioni a campo libero, tenendo però in considerazione che ogni referto e
messaggio è associato al dottore che lo ha scritto. Sono disponibili, inoltre, le opzioni per
la visualizzazione di altri messaggi e referti, nel caso si voglia tenere in considerazione una
seconda opinione. Attenzione a non dimenticare i vari stati di ogni singolo problema
clinico: dove il problema è classificato come “close” o “reported”, il dottore non potrà
effettuare la refertazione o aggiungere messaggi, infatti tale operazione è possibile solo per
lo stato “open” o “request another”.
L’interfaccia che si pone di fronte al requester è molto simile a quella del dottore. Il
requester in questa sezione può inserire i problemi clinici relativi ad un particolare
paziente. Alla creazione del problema clinico vengono richieste alcune informazioni.
Bisogna scegliere innanzitutto come classificare il problema, così da poter coinvolgere il
giusto dottore specializzato: si sceglierà la categoria dell’esame in base alle
specializzazioni mediche così da avere un semplice legame medico specializzazioneproblema clinico. A questo punto il requester deve inserire i sintomi che tale problema ha
mostrato e anche alcuni dati caratteristici del paziente come l’altezza, il peso, la pressione
sanguigna e la frequenza cardiaca, l’indice di massa corporea, delle considerazioni fisiche
e una conclusione esaustiva sul tutto. Ovviamente è possibile aggiungere un esame di
38
laboratorio effettuato per tale problema e fare l’upload sul server del file corrispondente.
Per quanto riguarda i problemi clinici già presenti, è possibile inserire nuovi esami di
laboratorio, così da dettagliare il problema. La procedura è identica a quella per
l’inserimento di un nuovo problema clinico, anche se qui non si andrà a creare un problema
clinico ma solo ad aggiungere un esame a quello esistente, vengono comunque chiesti i
dati del paziente sopra citati in quanto possono essere cambiati nel tempo. Il requester può
anche leggere i messaggi e soprattutto i referti dei dottori che hanno risposto: ogni referto o
messaggio contiene le informazioni relative all’ora, alla data e soprattutto da quale dottore
questo è stato emesso. Come sopra annunciato il requester può qui monitorare l’evento
decidendone la chiusura se è soddisfatto della refertazione o richiedere una nuova opinione
cambiando lo stato da “reported” in “request another”. La possibilità di richiedere
un’ulteriore analisi è a discrezione del requester e alla sua soddisfazione nel leggere le altre
diagnosi: non è prevista comunque nessuna limitazione in tal senso. Essendo nel campo
della telemedicina asincrona è possibile passare dallo stato “close” allo stato “request
another”, in quanto magari il problema non si è effettivamente risolto: questo può capitare
per via dell’inesperienza del requester, che si avvale di conoscenze mediche non sempre
all’altezza del problema che gli si pone e quindi potrebbe anche non riconoscere eventuali
sintomi presenti.
Come sopra accennato è qui che avviene il vero scambio di informazioni tra requester, e
quindi indirettamente tra il paziente, ed il dottore. Tutto il progetto Miro on Rails si basa
sullo scambio di tali informazioni e finalizza il suo intento in una diagnosi più precisa e
accurata possibile. Il tempo speso nel costruire la miglior cartella clinica possibile è quindi
tempo ben utilizzato per poter avere un risultato più corretto e rapido, senza continue
perdite di tempo dovute alla comunicazione asincrona tra le due figure in gioco.
39
3. PROGETTAZIONE
3.1 Architettura
L’architettura mostra la struttura generale e l’organizzazione del software; per questo tipo
di progettazione si può utilizzare il diagramma dei componenti.
Nel nostro caso il progetto riguarda la realizzazione di un middleware client-server e
quindi il punto di vista strutturale è “logica della applicazione distribuita”. Si è deciso di
organizzare il sistema nel modo seguente:
Figura 9: architettura
40
Middleware Client-Server
Il termine middleware si applica in generale allo strato di software, compreso tra il sistema
operativo e l’applicazione utente, che viene richiamato dall’applicazione in fase esecutiva e
sgrava l’applicazione da pesanti compiti generali di gestione non strettamente legati alle
sue funzionalità operative specifiche.
Con l’avvento dei PC utilizzati come stazioni di lavoro ed il diffondersi conseguente di
applicazioni client-server, i servizi di middleware cooperativo sono diventati sempre più
importanti. L’espressione client-server è molto generale e può riferirsi a quattro diversi
punti di vista:
• livello hardware: aumentare la scalabilità; sfruttare caratteristiche dei sistemi;
integrare applicazioni
• livello fisico del software: la collocazione delle parti dell’applicazione è rivolta alla
riduzione del traffico su rete e allo sfruttamento ottimale delle diverse risorse
• livello logico del software: si valutano le varie opzioni di distribuire logicamente i
compiti nell’applicazione
• livello
interno dell’applicazione: l’attenzione si sposta sulla separazione dei
compiti all’interno dell’applicazione, per aumentare la scalabilità, svincolarsi da
specifici fornitori di DBMS, scegliere tool di sviluppo ottimale, aumentare il riuso
del software
Miro on Rails è un middleware client-server a livello applicativo interposto tra l'utente
finale e il database. Esso è composto da un server web relazionale scritto in Ruby,
perfettamente adattabile a qualsiasi piattaforma e da tre classi di client, una per il refertante
(doctor), una per il richiedente (requester) e una per l’amministrazione (administrator). I
client si collegano al sistema direttamente tramite web browser, senza necessità di avere
installati componenti particolari. Il requisito della compatibilità è fondamentale specialmente
in ambiente remoto che può essere il più vario possibile.
41
3.2 Classi di progettazione
Una classe di progettazione è una classe le cui specifiche sono talmente complete da poter
essere effettivamente implementate, per ogni classe di analisi:
•
definire una classe di progettazione ed eventualmente una interfaccia
•
per la classe di progettazione completare l’insieme degli attributi della classe,
includendo tutte le specifiche: nome, tipo, visibilità
•
verificare che la classe di progettazione sia ben formata: completezza e sufficienza,
essenzialità, massima coesione, minima interdipendenza
Nel diagramma che segue sono state incluse tutte le specifiche, aggiunti tutti i costruttori
per accedere e modificare gli attributi, in base ai criteri di completezza ed essenzialità:
Figura 10: classi di progettazione
42
3.3 Progettazione cartella clinica
Vengono presentate ora le soluzioni tecnologiche utilizzate per la realizzazione della
cartella clinica. Una considerazione sugli argomenti trattati in questa sezione è che verrà
utilizzato impropriamente il termine pagina. Questo termine non rappresenta la nostra
realtà progettuale se si considera che con la tecnologia Ajax la pagina è sempre la stessa,
ma non perde neanche di significato se tale termine è utilizzato per esprimere le varie
“viste” disponibili all’utente. Con il termine pagina verrà quindi identificato ogni vista
visualizzabile dall’utente e sarà trattato come una pagina a sé.
La struttura della clinical folder è formata da due aree differenti, una laterale sinistra ed
una maggiore sulla destra che ricopre il resto della cartella. La parte laterale sinistra è
formata da una struttura ad albero, con questa soluzione sono ci sono due vantaggi: il
primo riguarda il fatto che l’utente ha sempre sotto controllo la posizione in cui sono i dati,
il secondo e più importante è che, in questo modo, nel lato sinistro della cartella clinica si
ha sempre una panoramica generale dei dati clinici del paziente.
Ovviamente la struttura ad albero è generica per tutti i pazienti, ma a seconda delle
informazioni cliniche che vengono inserite si modifica dinamicamente: ogni nodo sarà un
dato clinico sensibile del paziente ed è con esso che l’utente interagisce.
Un esempio può essere visto in figura:
Figura 11: clinical folder
43
La restante parte della cartella clinica è dove vengono visualizzate le informazioni non più
sotto forma di elenco, ma nel loro dettaglio.
Oltre a queste due aree sono disponibile alcuni strumenti per operare sui dati, utili
soprattutto per il requester. Sono infatti disponibili dei menu a tendina che permetto di
modificare, inserire o cancellare i dati corrispondenti alla pagina visualizzata. Oltre a
questi strumenti sono presenti i classici pulsanti di chiusura, di minimizzazione o
massimizzazione della cartella clinica.
Bisogna ricordare inoltre che ogni cartella clinica è personalizzata per ogni paziente e non
fornisce alcuna informazione sugli altri presenti nel database. Il funzionamento con cui
ogni cartella clinica è generata è molto semplice. Infatti nella sezione requester o dottore
compare un elenco dei vari pazienti disponibili da quell’utente, il quale selezionando un
paziente, avvia la procedura di apertura e visualizzazione della cartella clinica.
Clinical Folder
L’attivazione della clinical folder, avviene quando un dottore o un requester, tramite la
propria interfaccia grafica, seleziona un paziente o un clinical problem. Nel primo caso
come “vista” iniziale viene visualizzato il profilo del paziente, mentre nel secondo
l’attenzione è puntata sul problema scelto.
Analizziamo ora l’albero laterale che rappresenta la clinical folder. La sua costituzione è su
scala gerarchica, ovvero permette un solo nodo principale e successivamente vi sono tutti i
nodi figli, che a loro volta ne possono contenere altri. Nel nostro caso particolare abbiamo
dovuto dividere l’albero in due parti, una parte statica ed una asincrona (dinamica). La
parte statica rappresenta tutti quei nodi che non modificano la loro struttura, ovvero
lasciano inalterata la parte grafica ma anche le varie proprietà. La parte asincrona invece è
necessaria per tutti quei nodi che invece possono variare in struttura, è stata quindi
utilizzata per l’anamnesi.
44
Figura 12: struttura ad albero
La parte sincrona è creata essenzialmente tutta allo stesso modo. Vengono come prima
cosa impostate le proprietà necessarie, come l’identificativo nell’albero. Successivamente
viene impostato un evento che descrive l’azione da compiere quando viene selezionato il
nodo in questione: si dovrà aprire la “vista” rispettiva nel pannello centrale,
45
3.4 Confronto tra Ruby on Rails e tecnologie alternative
Si supponga di voler scrivere applicazioni (in particolare applicazioni web) solide e
facilmente manutibili, si hanno a disposizione varie alternative tra cui muoversi.
Java, nelle sue varie interpretazioni in forma di framework quali Struts, Java Server Faces
o Tapestry, è un opzione sicuramente valida e percorribile. Il punto debole della maggior
parte dei presentation frameworks in Java è tuttavia dato dal tempo di apprendimento
necessario ad essere produttivi, per una serie di motivi:
• i frameworks si evolvono, spesso più velocemente del supporto che può essere
offerto dall'IDE
• spesso da progetto a progetto il framework cambia
•
i framework sono complessi e necessitano della familiarità con il pattern MVC, con
XML, HTML, JSP, Tag Libraries, Servlet, etc.
Il risultato ottenuto sarebbe un' applicazione solida, ma, probabilmente non lo otterremmo
agevolemente e in maniera rapida. Inoltre il costo di manutenzione risulterebbe essere non
trascurabile.
Nell' eventualità in cui il contesto renda necessario il ricorso ad applicazioni J2EE di una
certa complessità, la scelta risulterebbe essere quasi obbligata nell'utilizzo di Java
Enterprise.
Uno dei punti di forza di Ruby è senza dubbio velocità di sviluppo e la semplicità di
manutenzione.
Premettendo che Java è un linguaggio maturo, testato ma anche molto "verboso", ciò che si
noterà abbastanza rapidamente passando a Ruby è la riduzione drastica delle righe di
codice scritto.
Ruby, come Java:
•
è un linguaggio interpretato
•
è un linguaggio OO (Object Oriented)
•
dispone di un Garbage Collector per la gestione della memoria
•
è portabile ed è utilizzabile con i principali sistemi operativi
•
ha oggetti fortemente "tipati"
46
• dispone di uno strumento di documentazione del sorgente (RDoc) molto simile a
JavaDoc
• ha "accessori" publici, protetti e privati, anche se il loro significato è diverso dai più
comuni linguaggi OO e da Java
a differenza di Java:
• il codice non necessità di compilazione.
• non è presente la dichiarazione del tipo
• è presente la keyword end per terminare classi, metodi e strutture in genere
• non sono presenti primitive
• non sono presenti interfacce, ma dispone di mix-in
• non è possibile fare overloading dei metodi
• ma soprattutto è "dynamically typed"
E' giunto il momento di focalizzare l'attenzione su un insieme di possibili rischi
nell'adottare Ruby come linguaggio di programmazione al posto di Java:
¾ Come ogni nuovo linguaggio Ruby potrebbe stagnare, il che comporterebbe a una
ricerca delle risorse sempre più difficile da effettuare.
¾ Non ci sono ancora molte applicazioni Ruby pubblicate e quindi non si hanno molte
dimostrazioni sulla massima scalabilità del linguaggio.
¾ La comunità di Ruby non ha le dimensioni che la comunità di Java ha raggiunto, in
questo modo risulta più difficile trovare componenti di terze parti, frameworks e
servizi.
¾ Ruby è meno strutturato di Java e ha meno caratteristiche automatizzate per
proteggere le applicazioni dagli abusi, questa flessibilità è sia un punto di forza che
di debolezza.
i vantaggi di Java:
¾ La comunità Java è enorme, è possibile trovare sempre sviluppatori da assumere o
consultare.
47
¾ La popolazione open source di Java cresce in continuazione. Con Java, è possibile
ottenere software libero.
¾ Java è maturo ed è ancora la scelta più sicura.
¾ Java è scalabile.
¾ Java offre molta scelta. Ci sono molti standards aperti che definiscono interfacce e
fornitori da qui scegliere.
¾ Ruby è relativamente nuovo, e non ha molti frameworks disponibili come Java.
Infatti se c'è da sviluppare un progetto che richiede particolari caratteristiche, si
possono trovare molte librerie in Java ma non in Ruby.
Per queste ragioni Java ha dominato nel campo delle applicazioni web. Sicuramente Java
può gestire le situazioni più complicate:
•
Two-phase commit: quando le applicazioni devono coordinare due risorse, come ad
esempio due database, c'è bisogno di programmi sofisticati per collegare i due. Questi
software usano spesso il two-pahse commit, e java lo supporta.
•
Oggetti distribuiti: Java può gestirli in molti modi, invece le opzioni di ruby sono più
limitate.
Produttività
In molti casi la produttività è il fattore più importante nello sviluppo di un software. Se il
proprio progetto deve essere enfatizzato per la qualità, caratteristiche, disponibilità, o
performance, la produttivita è la chiave per ottenere ciò. I migliori team di sviluppo
costruiscono software in tre fasi:
1) Nella prima si ha l'obbiettivo di farlo funzionare.
2) Nella seconda quello di renderlo corretto (qualità).
3) Infine di renderlo veloce (performance).
Con una maggiore produttività, si ha più tempo per concentrarsi sul miglioramento delle
caratteristiche, delle performance, e sulla qualità.
48
La produttività con il linguaggio Java:
Nel 1996, C++ era il linguaggio di programmazione per lo sviluppo di applicazioni su
piattaforme server. Il C++ non era un linguaggio molto produttivo, ma era veloce. A quel
tempo la velocità era molto più importante della produttività.
C++ aveva la comunità e il mercato ma quando ci furono condizioni favorevoli, emersero
nuovi linguaggi di programmazione e i più vecchi sparirono.
Questi linguaggi di programmazione necessitavano di una comunità per raggiungere la
diffusione, ma era difficile ottenere nuovi utenti senza averne già una.
Quando Sun ha creato Java, ha accettato qualche compromesso per poter incrementare la
comunità in tempi assai brevi:
¾ Sun ha fatto Java simile a C++. Java ha una sintassi paragonabile a quella del C++.
In questo modo non c'è stato il bisogno di creare una comunità dal nulla.
¾ C++ presenta anche dati primitivi che non sono oggetti, come caratteri e numeri.
Java ha effettuato la stessa scelta.
¾ Sun come C++ ha adottato la caratteristica chiamata static typing. Static typing sta
indicare che a ogni variabile viene associato rigidamente un tipo che rimane lo
stesso per tutto il programma. La maggior parte dei linguaggi più produttivi usa una
strategia differente, chiamata dynamic typing.
¾ I programmi scritti in Java hanno una lunghezza del codice maggiore degli stessi
programmi scritti in linguaggi dinamici come Ruby. Molti pensano che programmi
più brevi riducano i costi di mantenimento in maniera proporzionale.
¾ Lo static typing di Java richiede un compilatore, così il compilatore può controllare
certi dettagli per i programmatori, come le forme di compatibilità tra due parti di un
programma. Come conseguenza, gli sviluppatori Java devono effettuare molte
compilazioni. Gli sviluppatori ruby non ne hanno bisogno.
¾ Le primitive Java, non oggetti; questo significa che le librerie Java sono spesso più
grandi delle librerie per linguaggi puramente orientati agli oggetti.
49
Una possibile alternativa a Ruby on Rails
Una possibile combinazione di tecnologie open source, alternative a Ruby on Rails, che
uno sviluppatore potrebbe utilizzare per risolvere i problemi è questa:
¾ Il framework MVC Struts permette di separare modelli, viste e controllers. La
maggior parte degli sviluppatori ricorrono a opzioni come Tapestry e JSF
(JavaServer Faces) che stanno emergendo, ma Struts è il più popolare tra i
framework MVC.
¾ Il framework Spring un che ha come obiettivo principale quello di gestire la
complessità nello sviluppo di applicazioni "enterprise" in ambiente Java.
¾ Hibernate permette di accedere ai database relazionali attraverso i tradizionali
oggetti Java.
Ognuna di queste tecnologie permette ai programmatori di scrivere codice con tempi
minori rispetto ai frameworks Java tradizionali ma c'è un costo: sono complessi.
Considerazioni sui costi
Ridurre la complessità del progetto attraverso il miglioramento dei processi di sviluppo o
del linguaggio di sviluppo comporta diversi benefici.
La scelta di un linguaggio di programmazione può influenzare i costi:
•
Più produttività porta ad aver bisogno di un numero minore di sviluppatori per
progetto.
•
Si spende meno fatica sulla comunicazione per piccoli progetti.
•
Avere meno sviluppatori per progetto comporta anche costi di managment minori per
progetto.
50
Utilizzo di un framework con Ruby e con Java
Task
Ruby
Java
Installare un framework
gem install framework
• Identificare tutte le dipendenze
• Installare ogni dipendenza
• Installare il framework
Configurarlo
• Configurazione minima
• Installare le librerie necessarie
con gem
• Eseguire l'applicazione
•
Aggiungere
le
librerie
necessarie al progetto
•
Settare
le
variabili
come
classpath
• Configurare con XML
•
Compilare
e
eseguire
l'applicazione
Scegliere un framework
• Poche scelte
• Molte scelte con differenti
trade-offs
51
3.4.1 Rails
Rails è un un framework open source per applicazioni Web, altamente produttivo, che
implementa strettamente, e in maniera pressochè automatica, il pattern MVC. Dispone di
uno strumento ORM molto potente e risulta ideale per la creazione di una "classica"
applicazione web basata su DBMS.
Gli obiettivi che RoR cerca di raggiungere sono.
DRY (Don't Repeat Yourself): si riferisce al concetto secondo il quale non ci debbano
essere duplicazioni in una applicazione Rails. Ogni idea deve essere espressa una sola
volta. Questo obiettivo viene raggiunto utilizzando il linguaggio Ruby.
Convention Over Configuration: questo concetto è forse il più importante tra quellli qui
elencati. Si riferisce al fatto che Rails ha "sensible default" per pressoché ogni componente
dell'applicazione. Questo implica che il lavoro principale si riduce a mettere insieme i
pezzi piuttosto che programmare.
Agility: il concetto fa parte della struttura di Rails. Nella struttura del framework il
concetto è già implicito con una serie di strumenti che orientano (e spingono quasi) il
programmatore a questo approccio.
Dal punto di vista architetturale RoR non si discosta troppo da una classica applicazione
Web basata su di un framework Java tipo Struts. Se a questo si aggiunge poi uno strumento
ORM (tipo Hibernate) per il mapping del DB, le differenze si limitano al linguaggio e ad
alcune convenzioni specifiche del framework.
Facendo un confronto con Struts, il framework per applicazioni web Java più utilizzato, si
nota come in Rails non sono presenti file (xml) di configurazione (struts.xml) con il fine di
mettere insieme le varie componenti dell'applicazione (realizzate in maniera indipendente)
ma ci si basa piuttosto sulla semantica. Ovviamente tutte le convenzioni utilizzate sono
suscettibili di override.
52
Sicuramente Ruby e Rails risultano essere sufficientemente maturi per implementazioni in
contesti "non enterprise" non in cui non si hanno di solide, ma costose applicazioni Java
EE, Rails fornisce una valida soluzione Ajax-based, MVC e Object Oriented.
Progetto
Linguagg Ajax
MVC
I18n
io
Framewo
i10n
& ORM
Testing
DB
Security
framewor migration Framewo
framewor rk(s)
k(s)
rk
Template
Caching
Form
Validation
Framewo
Framewo
Framework(s)
rk(s)
rk(s)
k(s)
Si, Active Si,
Si, Active Si,
Ruby on Ruby
Si,
Rails
Prototype Record e Localizati Record
&
Action
script.acu Pack
Unit Si
Tests,
on Plug-
Functiona
in
l Tests e
Si, plug- Si
Si
Si
in
Integratio
lo.us
n Tests
Tapestry
Google
Java
Java
Si
Si
Si
Si
Si
Si,
Si,
integrato
tapestry5-
con
acegi
Hibernate
library
Si
Si, built-in validation
system
Si,
Web
integrato
Toolkit
con
Hibernate
53
4. IMPLEMENTAZIONE LATO CLIENT
4.1 Realizzazione Database
Figura 13: database andromeda
Abbiamo chiamato il database “andromeda” e presenta 21 tabelle come si vede in figura
13. Ora esaminiamo singolarmente la struttura delle tabelle:
Tabella
Funzione
Collegamento
allergies
elenca le possibili allergie
anamnesis_allergologies
allergy_categories
elenca le categorie di allergie
allergies
anamnesis_allergologies
contiene le allergie di ogni
paziente
54
Tabella
anamnesis_familiars
Funzione
Collegamento
contiene le informazioni sui
familiari di ogni paziente
anamnesis_family_pathologies contiene le patologie
parenti di ogni paziente
dei
anamnesis_pathologicals
contiene le patologie di ogni anamnesis_allergologies
paziente
anamnesis_phisyologicals
contiene
informazioni allergies
fisiologiche su ogni paziente
ecgs
contiene i dati di ogni ECG
effettuato
events
contiene i problemi clinici dei visits, forums, reports
pazienti
exams
contiene l’elenco degli esami
exams_users
contiene l’elenco dei pazienti visits, exams, users
da collegare agli esami o
problemi clinici
exam_files
contiene
allegati
forums
contiene i messaggi che si
possono scambiare i dottori
laboratory_exams
contiene i dati di laboratorio
locations
contiene informazioni su structures, users
residenza e luogo di nascita
pathologies
elenca le possibili patologie
patients
contiene i dati generici di ogni tabelle anamnesis, visits,
paziente
events
reports
contiene i referti fatti dai
dottori sugli esami dei
problemi clinici
structures
contiene i dati sulle strutture patients, users
ospedaliere
l’elenco
dei
file
anamnesis_pathologicals
,anamnesis_family_path
ologies
55
users
contiene i dati di ogni tipo di patients,
utente
(administrator, exams_users,
requester, doctor)
reports, forums
visits,
events,
visits
contiene i dati degli esami dei ecgs,
exams_file,
pazienti
laboratori_exams
Di seguito sarà riportato lo schema E-R del database:
Figura 14: schema E-R database
56
4.2 Ambiente di sviluppo e tecnologie software utilizzate
In questa sezione tratteremo in modo dettagliato gli aspetti implementativi che
caratterizzano il progetto. In particolare focalizzaremo l’attenzione sui framework
impiegati, l’ambiente di sviluppo, i linguaggi di programmazione e tutte le tecnologie di
supporto alla realizzazione di Miro on Rails.
4.2.1 Eclipse con plugin Aptana + Radrails + Ruby
Eclipse è un progetto open source legato alla creazione e allo sviluppo di un IDE (sistema
di sviluppo integrato) ideato da un consorzio di grandi società, chiamato Eclipse
Foundation, e creata da una comunità strutturata sullo stile dell'open source. E’ disponibile
per le piattaforme Linux, HP-UX, AIX, Mac OS X e Windows.
Il programma è scritto in Java, ma utilizza delle librerie grafiche diverse da quelle della
Sun Microsystems in modo da rendere più veloce la visualizzazione (ecco perchè è così
lento all'avvio...).
La piattaforma di sviluppo è incentrata sull'uso di plug-in, delle componenti software
ideate per uno specifico scopo (per esempio la generazione di diagrammi UML) ed in
effetti tutta la piattaforma è un insieme di plug-in, versione base compresa, che chiunque
può sviluppare e modificare. Nella versione base è possibile programmare in Java, con
funzioni di aiuto come completamento automatico, suggerimento dei tipi di parametri dei
metodi, possibilità di accesso diretto a CVS e riscrittura automatica del codice in caso di
cambiamenti nelle classi.
Eclipse non è un editor, ma un ambiente di sviluppo; non si può, ad esempio, aprire e
compilare un qualunque file. Per usare questo IDE bisogna organizzare il proprio lavoro in
progetti. Un progetto è l'insieme di file e impostazioni relativi ad un programma che si sta
sviluppando. Nel caso di Java, ad esempio, il progetto conterrà non solo i file sorgenti .java
ma anche l'indicazione di quale JDK usare, le librerie esterne (file .jar) e altro.
Per "workspace" si intende la directory in cui vengono salvati i progetti. Al primo avvio
viene suggerita una cartella all'interno della cartella di installazione di Eclipse, ma questa a
lungo termine non è la scelta migliore. Se si seleziona una cartella esterna si può
successivamente usare una nuova versione di Eclipse senza problemi.
57
Con Eclipse è possibile cambiare l'interfaccia grafica in base a quello che si sta facendo.
Una "prospettiva" è un modo di vedere il progetto (cioè organizzare l'interfaccia grafica) e
modificarlo nella maniera più comoda. Ad esempio, è possibile programmare nella
prospettiva "Java", organizzare i file in "Resource", eseguire debug in "Debug", etc etc.
Questa organizzazione dell'interfaccia permette di avere sottomano i comandi
immediatamente utili e non dover ricordare mille scorciatoie di tastiera.
I numerosissimi plugin di Eclipse sfruttano questa caratteristica per offrire funzionalià non
solo testuali (editor, debug, ...) ma anche grafiche (come il plugin di supporto agli schemi
UML).
Rimanendo sempre nella metafora visuale una prospettiva è composta da "viste". Una vista
è una tab che solitamente visualizza un output o un qualche genere di struttura.
Esempi di viste:
9 "Navigator": visualizza i file contenuti in un progetto.
9 "Console": alla stregua della console riceve input e mostra l'output del programma.
9 "Problems": evidenzia i problemi di compilazione del programma.
Le prospettive possono essere personalizzate spostando, aggiungendo o eliminando le
viste. In questo modo si può avere l'interfaccia più congeniale al lavoro che si sta facendo.
Le views posso essere chiuse, spostate, ridotte o ingrandite. Con Ctrl+F6 ci si può spostare
nelle tab dei file aperti nell'editor, tenendo premuto Ctrl e usando le frecce direzionali.
Plugin APTANA
Aptana, Inc. fondata da Paul Colton nel 2005 ha come obbiettivo la creazione di strumenti
e prodotti destinati a sviluppatori web che usano linguaggi di scripting (JavaScript, Ruby,
PHP and Python) per il Web 2.0 e lo sviluppo di applicazioni Ajax. I principali prodotti di
aptana sono Aptana Studio, Aptana Cloud and Aptana Jaxer.
Aptana Studio è un ambiente di sviluppo integrato open source (IDE) per la creazione di
applicazioni Web Ajax. Esso comprende supporto per Javascript, HTML, DOM, CSS con
completamento del codice, outlining, JavaScript debugging, notifica di error e warning e
58
documentazione integrata. Aptana studio fornisce anche plugins per estendere il supporto
anche a Ruby on Rails, PHP, Python, Adobe AIR, e Apple iPhone.
Aptana Studio è basato su Eclipse ed è disponibile per Microsoft Windows, Mac Os e linux
oppure come plugin per Eclipse.
Requisiti di sistema:
• Windows - 512 MB RAM, Pentium 4
• Mac OS - 512 MB RAM, G5 or Intel
• Linux - 512 MB RAM, Pentium 4
Radrails è un IDE per il framework Ruby on Rails. L'obbiettivo di questo progetto è
fornire ai programmatori Rails ogni cosa di cui hanno bisogno per sviluppare, gestire,
testare e pubblicare le loro applicazioni. Le caratteristiche includono il controllo del
codice, code assist, refactoring, debugging, servers WEBrick, generatori e strumenti per la
gestione dei dati.
L' IDE RadRails è basato su Eclipse RCP e include i plugin RDT e Subclipse. RadRails è
anche disponibili sotto forma di plugins.
CARATTERISTICHE
Web:
• Free e open source; multipiattaforma, stand-alone IDE o plug-in Eclipse
• Real-time, help online basato su Wiki; IDE tradotto in più lingue
• Scriptable usando JavaScript (“Aptana Monkey”)
• Supporto (con suggerimenti per vari browser) per JavaScript, HTML, CSS
• Syntax highlighting, auto completion, code assist, error reporting, etc.
• Pieno supporto a JavaScript e CSS dentro il codice HTML
• Lavora con tutte le librerie Ajax
• Il debugger JavaScript ha integrato Firebug
Rails:
• Pieno supporto a Ruby, Rails, RHTML, JS, HTML e CSS.
59
• Syntax highlighting, auto completion, code assist, error reporting, outlining
• Generazione di codice Ruby: costruttori, templates, accessors
• Refactoring
• Debugger integrato
• Supporto per i generatori Rails, Rake, plugins, e gestione del server
• Navigatore del database e console per le query
• help integrato
4.2.2 SSH
SSH (Secure SHell, shell sicura) è un protocollo che permette di stabilire una sessione
remota cifrata ad interfaccia a linea di comando con un altro host.
Il client SSH ha una interfaccia a linea di comando simile a quella di telnet e rlogin, ma
l'intera comunicazione (ovvero sia l'autenticazione che la sessione di lavoro) avviene in
maniera cifrata. Per questo motivo, SSH è diventato uno standard di fatto per
l'amministrazione remota di sistemi unix e di dispositivi di rete, rendendo obsoleto il
protocollo telnet, giudicato troppo pericoloso per la sua mancanza di protezione contro le
intercettazioni.
Il client ed il server SSH sono installati o installabili su molte versioni di UNIX, Linux,
Mac OS X e Microsoft Windows, inoltre è disponibile come strumento di amministrazione
su alcuni apparati di rete.
Port forwarding
SSH permette di realizzare dei tunnel criptati, che permettono di trasportare sessioni TCP
arbitrarie all'interno della connessione criptata, permettendo di proteggere da
intercettazione protocolli non sicuri, o di aggirare limitazioni di routing.
Questa funzionalità è detta port forwarding, e permette di aprire un socket TCP sul client
SSH (local port forwarding) o sul server (remote port forwarding). Le connessioni ricevute
su questa porta vengono inoltrate dall'altro capo della connessione SSH, verso un host e
una porta specificata.
Ad esempio, con questo comando ci si collega ad host1, inoltrando la porta 10022 della
60
macchina in cui lanciamo il client ssh alla porta 22 di host2 attraverso un canale sicuro
tra client e host1.
X forwarding
Il port forwarding è utile anche per trasportare applicazioni X Window attraverso una
connessione SSH. SSH imposta anche automaticamente le opportune variabili d'ambiente,
in modo che le applicazioni X lanciate da un terminale remoto vengano visualizzate sul
display da cui è stata avviata la connessione.
L'X forwarding dal lato client deve essere abilitato passando l'opzione "-X" mentre dal lato
server va modificato il file di configurazione /etc/ssh/sshd_config abilitando la direttiva
X11Forwarding.
Meccanismi di autenticazione del client
Esistono principalmente due metodi di autenticazione per controllare l'accesso ad un server
ssh:
•
Username/Password: l'utente fornisce un nome utente ed una password, che vengono
validati dal server. Questo scambio avviene all'interno di un canale cifrato, per cui non
è a rischio di intercettazione.
Procedura:
1. A => B: SSH_MSG_USERAUTH_REQUEST, pappy, ssh-userauth, keyboardinteractive
2. B => A: SSH_MSG_USERAUTH_INFO_REQUEST, pappy, passwordauthentication, 1, "Enter Password"
3. A => B: SSH_MSG_USERAUTH_INFO_RESPONSE, 1, "love"
4. B => A: SSH_MSG_USERAUTH_SUCCESS
•
Chiave pubblica: questo metodo di autenticazione è basato sulla crittografia
asimmetrica. Per utilizzarlo l'utente genera una coppia di chiavi. La chiave pubblica è
copiata sul server, tipicamente in un apposito file nella home directory dell'utente; la
chiave privata deve essere conservata dall'utente, ed è bene che sia protetta con una
61
parola chiave (passphrase).
Nella fase di accesso, il client ssh prova al server di essere in possesso della chiave privata,
e in caso di successo viene consentito l'accesso. In questo modo, all'utente non è richiesto
di fornire la propria password ad ogni connessione.
Autenticazione del Server
SSH prevede anche la verifica dell'autenticità del server. Questo serve ad evitare che un
utente maligno "impersoni" il server, facendosi fornire le credenziali dell'utente (attacco
man in the middle). A questo scopo, per ciascun server viene generata una coppia di chiavi
asimmetriche. La chiave privata rimane sul server, la chiave pubblica deve essere installata
sui client. Quando un client si collega ad un server di cui conosce la chiave pubblica,
verifica che il server sia ancora in possesso della chiave privata. Se questa verifica fallisce,
la connessione viene abbattuta, evitando di fornire credenziali al server.
Nella pratica, quando ci si collega ad un server per la prima volta, il client chiede se si
vuole accettare la chiave pubblica di questo server, e se l'utente risponde positivamente
memorizza questa chiave e prosegue nella connessione. Alle connessioni successive con lo
stesso server, il client ne verifica l'autenticità, e nel caso la chiave privata non corrisponda
impedisce di proseguire la connessione.
OpenSSH (Open Secure Shell) è un insieme di programmi che rendono disponibili sessioni
crittografate di comunicazione in una rete di computer usando il protocollo SSH. È stato
creato come alternativa opensource al software proprietario Secure Shell.
Poiché OpenSSH deve supportare l'autenticazione, una funzione che ha svariate
implementazioni
nei diversi sistemi operativi, necessita di una infrastuttura per la
portabilità. Piuttosto che includerla direttamente all'interno di OpenBSD o OpenSSH,
viene sviluppata separatamente come sotto progetto dal OpenSSH Portability Team, e
rilasciata come "portable releases". Questo modello viene utilizzato anche per altri progetti
BSD come OpenNTPD.
La suite OpenSSH include le seguenti utilità:
• ssh, un rimpiazzo per rlogin e telnet: ssh [email protected]
• SCP, un rimpiazzo rcp: scp [email protected]:~/somefile
62
• SFTP, la versione sicura di ftp: sftp [email protected]
• sshd, il demone SSH: sshd
Configurare SSH
E' possibile installare SSH digitando da shell:
sudo apt-get install ssh
che provvederà ad installare automaticamente il daemon SSH che fungerà da Server.
Una volta installato è possibile trovare i file di configurazione in :
/etc/ssh
e il file che bisogna modificare per configurare in modo corretto il Server SSH è
/etc/ssh/sshd_config
Una volta aperto con un editor di testo è possibile trovare i seguenti parametri:
•
Port 22
di default viene aperta la porta 22 per questioni di sicurezza e per
evitare si essere trovata da un portscan occasionale è consigliato cambiarla
possibilmente scegliendone una superiore alla 1024, in quanto fino alla 1024 sono
riservate per servizi noti.
•
ListenAddress 0.0.0.0
di default è 0.0.0.0 che indica l’ascolto in tutte
le interfacce di rete configurate e tutti gli indirizzi IP associati, pertanto è utile
cambiarlo con l’indirizzo IP specifico nel quale ci si aspettano connessioni.
•
HostKey /etc/ssh/ssh_host_key
specifica la posizione che contiene
le chiavi private di un host e può essere lasciato il valore di default. Possono essere
specificati più files ripetendo HostKey e cambiando il file di destinazione.
•
Protocol 2
indica il protocollo da utilizzare. Possono essere indicati 1 o 2 o
entrambi separandoli con la virgola (1,2), tuttavia non è consigliato permettere
connessioni con il protocollo 1.
63
•
UsePrivilegeSeparation yes
yes è il valore di default, e indica che per
ogni login viene creato un processo figlio con i privilegi dell’user che ha effettuato il
login per evitare tecniche di “privilege escalation” basati sui privilegi dei processi.
•
ServerKeyBits 1024
dice quanti bit devono essere utilizzati per la
creazione della chiave di criptazione della connessione. Si preferisce di solito utilizzare
1024 che è un buon compromesso tra velocità ed efficacia di criptazione.
•
LoginGraceTime 120
rappresenta il tempo massimo in secondi che
intercorre tra il momento in cui viene stabilita la connessione e quello in cui avviene un
login con successo.
•
KeyRegenerationInterval 3600
rappresenta il massimo tempo in
secondi che il demone aspetta prima di rigenerare una nuova chiave per la connessione
corrente e non deve essere eccessivamente elevato per evitare il cracking della chiave
utilizzata nella sessione corrente.
•
PermitRootLogin no
in genere di default è impostato su yes ma è
altamente sconsigliato permettere ad un utente di effettuare il login remoto come root;
è molto più sicuro far si che si effettui un login come normal user e da li guadagnare i
permessi di root.
•
IgnoreRhosts
yes
dichiara di ignorare i files rhosts e shosts per
l’autenticazione.
•
IgnoreUserKnownHosts yes
hosts
conosciuti
presente
dice al daemon di ignorare la lista degli
in
$HOME/.ssh/known_hosts
durante
la
RhostsRSAAuthentication.
•
StrictModes yes
questo serve per proteggere i files nelle home degli user
che di solito vengono lasciati “world-writable”.
64
•
X11Forwarding no
permette di disabilitare o abilitare il forwarding su X11.
Se non è presente una GUI installata nel server viene settato a no.
•
PrintMotd yes
•
IgnoreUserKnownHost yes
abilita la visualizzazione di /etc/motd a login avvenuto.
si ignora l’utilizzo di ~/.ssh/known_host e per
il login ci si basa unicamente su user e password.
•
SyslogFacility AUTH
•
LogLevel INFO
ci indica il grado di prolissità dei log. I valori possibili sono
QUIET, FATAL, ERROR, INFO, VERBOSE, DEBUG, DEBUG1, DEBUG2,
DEBUG3. Utilizzare un flag di DEBUG viola la privacy degli utenti pertanto non è
consigliato.
•
RSAAuthentication yes
•
PasswordAuthentication yes
indica se sono concessi i login con solo RSA.
indica se utilizzare come metodo di
accesso le password o meno.
•
PermitEmptyPasswords no
non permette i login senza user o senza
password.
•
AllowUsers mironrails
permette il login via SSH solo agli user
specificati. Da notare che gli user sono separati da spazi vuoti, quindi niente virgole o
punto o altro
Una volta configurato il sistema per effettuare il login al server di miro on rails è sufficente
lanciare da shell il seguente comando: “ssh -l mironrails 193.205.130.163” e inserire la
password.
65
4.2.3 Prototype
Prototype è un Framework JavaScript che mira a facilitare lo sviluppo di applicazioni web
dinamiche.
Offrendo un toolkit per lo sviluppo basato sulle classi unico e facile da usare e la migliore
libreria Ajax attualmente disponibile, Prototype sta velocemente diventando il termine di
paragone per gli sviluppatori di applicazioni.
Funzionalità:
• Sviluppo semplice di applicazioni Ajax: Oltre che semplici richieste, questo
modulo gestisce in maniera intelligente anche il codice JavaScript restituito dal
server e fornisce classi helper per il polling.
• Estensioni DOM: aggiunge diversi e utili metodi agli elementi restituiti dalla
funzione
$(),
ad
esempio,
potete
scrivere
$(’comments’).addClassName(’active’).show() per prendere l’elemento con l’ID
‘comments’, aggiungere una classe e visualizzarla (se precedentemente nascosta).
• Utilizzo di JSON (JavaScript Object Notation): JSON è un’alternativa veloce e
leggera a XML nelle richieste ti tipo Ajax.
Prototype non è un framework di sviluppo di applicazioni completo: non fornisce widgets
o set di algoritmi standard o sistemi di I/O.
Nonostante sia stato progettato per il linguaggio di programmazione Ruby, Prototype non è
legato a nessuna tecnologia lato server.
Prototype è distribuito come un singolo file chiamato prototype.js, pesante circa 120KB
nella versione non compressa altrimenti sui 50KB.
Abilitare Prototype in una pagina web è veramente semplice, è infatti sufficiente caricare
prototype.js come qualsiasi altro file Javascript:
<head>...
<script type="text/javascript" src=".../prototype.js" ></script>
...</head>
66
4.2.4 Ajax
AJAX (acronimo di Asynchronous JavaScript and XML) è una tecnica di sviluppo che si
sta proponendo sul fronte delle applicazioni web interattive. L’obiettivo è quello di
migliorare l’interattività, la velocità e l’usabilità delle pagine web. Questo avviene grazie
allo scambio in background di pacchetti di dati, di piccole dimensione, con il server, in
modo da non dover ricaricare l’intera pagina ogni volta che l’utente apporta delle
modifiche. La tecnica AJAX utilizza una combinazione di diversi paradigmi
d’implementazione, quali:
•
HTML (o XHTML) e CSS per la parte visiva;
•
DOM (Document Object Model) modificato attraverso un linguaggio come il
Javascript per mostrare dinamicamente le informazioni e interagirvi;
•
L'oggetto XMLHttpRequest per interscambiare in modo asincrono i dati tra il browser
dell’utente e il webserver. In genere viene utilizzato l’XML come formato di scambio
dati, anche se possono essere utilizzate altre tecnologie come l'HTML preformattato,
testo semplice, JSON e perfino EBML. Questi file vengono generati di solito in modo
dinamico da script lato server.
Il fondamento della versatilità di questa tecnica è proprio nell’oggetto XMLHttpRequest. A
seconda del browser che si utilizza, prende nomi differenti oppure viene richiamato in
maniera diversa. Nel caso di Internet Explorer, ad esempio è restituito da un
ActiveXObject, mentre in altri browser come Mozilla, Firefox, Safari questo oggetto è
supportato nativamente. La sua manipolazione permette di effettuare la richiesta asincrona
di una risorsa ad un server web, in maniera indipendente dal browser.
Il fatto che la richiesta sia di tipo asincrono, significa che per effettuare altre operazione
non bisogna necessariamente attendere che sia stata completata, anche se da un certo punto
di vista è come se stravolgessimo il tipico flusso di dati di una pagina web. Ciò che resta
del vecchio flusso è il tempo di attesa, ossia il tempo che trascorre tra una richiesta
dell’utente e la risposta del server, che è considerato uno dei maggiori problemi
dell’utilizzo di AJAX, sia per sviluppatori che per gli utenti normali.
67
Lato Client
Avendo a che fare con questo tipo di applicazioni, abbiamo subito l’impressione di avere a
che fare con pagine apparentemente più interattive, dinamiche e professionali. Questo tipo
di aspetti che possono sembrare superficiali , hanno invece permesso l’affermazione di
tecnologie come il Flash nel contesto web. L’oggetto XMLHtttpRequest , grazie alla sua
compatibilità totale con i browser più diffusi ed il supporto nativo o integrabile, ha reso
possibile l’accrescimento dello sviluppo delle applicazioni internet, allargando i campi di
impiego per gli sviluppatori e coinvolgendo sempre di più gli utenti, che potranno trarre
numerosi vantaggi da AJAX. Per contro, bisogna tener conto di certe penalizzazioni,
soprattutto nei confronti degli utenti che necessitano di tecnologie di assistenza e quelli che
non dispongono di connessioni abbastanza veloci. Questo perché non potranno sfruttare
tutte le potenzialità o perché, almeno la prima volta, dovranno caricare una grossa mole di
dati (i vari file Javascript) e quindi potrebbero non riuscire a sfruttare nulla di quanto
caricato. Tra i problemi tecnici che si possono verificare, potremmo avere casi di
Javascript disabilitato , browser non aggiornati o assenza dell’oggetto XMLHttpRequest.
Dal punto di vista pratico il problema più fastidioso e noto che si può riscontrare è quello
relativo alle frecce presenti nel browser. Ogni interazione asincrona , ci dà la sensazione di
aver cambiato stato alla pagina e quindi si ha l’abitudine a tornare indietro ciccando sulla
freccia “indietro” del browser. In realtà però si verrà reindirizzati alla pagina precedente.
Questo problema , oltre ad essere un vincolo di navigazione è anche un vincolo per
l’indicizzazione o la possibilità di segnalare agli altri una pagina da noi visualizzata.
68
4.2.5 Mantis bug tracker
Durante la fase di testing e monitoraggio di Miro on Rails abbiamo utilizzato uno
strumento che ci ha permesso di avere una base comune per la comunicazione di eventuali
bug o malfunzionamenti. La scelta è caduta su un software open source in linea con la
nostra filosofia progettuale, Mantis bug tracker:
Mantis Bug Tracker
Victor Boctor
Sviluppatore:
Ultima versione:
Ultima beta:
1.1.4 / novembre 2008
1.2.0a2 / novembre 2008
Multipiattaforma
SO:
PHP
Linguaggio:
Genere:
Bugtracker
Licenza:
GNU GPL
Sito web:
http://www.mantisbt.org/
Mantis Bug Tracker è un software lato server scritto in PHP e si può appoggiare a diversi
database: MySQL, MSSQL, DB2, Oracle e PostgreSQL. E’ rilasciato sotto la licenza GNU
General Public License (è una licenza per software libero).
69
Funzionalità:
•
E' possibile farlo funzionare solamente con un webserver e un database, su
qualunque sistema operativo
•
Possibilità di scelta tra 68 lingue differenti
•
Generazione automatica di ChangeLog ("Registro delle modifiche"). Il ChangeLog,
di solito memorizzato su un file di testo, raccoglie, in ordine cronologico, tutti i
possibili riferimenti di rintracciabilità di ogni modifica effettuata ad un progetto
fino alla release attuale. Un ChangeLog, per ogni modifica, deve riportarne almeno
la release di intervento, l'autore, la data, la descrizione, le motivazioni ed
eventualmente la versione.
•
Generazione automatica di Roadmap
•
Visualizzazione di Report peronalizzati per ogni utente
•
Completa personalizzazione di ogni opzione del bug: permette di aggiungere nuovi
campi ed eliminare quelli predefiniti
•
Sistema di ricerca con filtri
•
Supporto per 1 o più progetti, ognuno dei quali con politiche di accesso differenti
•
Creazione di sottoprogetti e categorie di progetti
•
Esportazioni csv, Microsoft Word e Microsoft Excel
•
Integrazione di una Wiki (MediaWiki,DokuWiki, XWiki e TWiki): sito web (o
comunque una collezione di documenti ipertestuali) che può essere modificato dai
suoi utilizzatori e i cui contenuti sono sviluppati in collaborazione da tutti coloro
che ne hanno accesso, come in un forum. La modifica dei contenuti è aperta e
libera, ma viene registrata in una cronologia permettendo in caso di necessità di
riportare la parte interessata alla versione precedente; lo scopo è quello di
condividere, scambiare, immagazzinare e ottimizzare la conoscenza in modo
collaborativo
70
Requisiti:
•
•
Mantis 1.1.x
¾
PHP 4.3.0 o superiore
¾
MySQL 4.1.1 o superiori (MS SQL e DB2 sono già supportati)
¾
Web server (Apache, IIS, ecc.)
Mantis 1.2.x
¾
PHP 5.1.0 o superiori
¾
MySQL 4.1.1 o superiori (MS SQL, DB2. Oracle e PostgreSQL sono supportati
ma in via sperimentale)
¾
Web server (Apache, IIS, ecc.)
71
4.2.6 Sistema Operativo
Miro On Rails è un Middleware Client-Server, rappresenta uno strato software comune
all’eterogeneità di classi client che interagiscono con il database centrale. Infatti ogni client
hai il proprio sistema operativo, quindi dal lato client ci siamo preoccupati di
esclusivamente della corretta progettazione e implementazione del Middleware.
Per il server centrale invece abbiamo utilizzato il sistema operativo Ubuntu 8.04 Hardy
Heron. Ubuntu è un sistema operativo open source basato sul kernel Linux. La comunità di
Ubuntu è fondata sull'idea insita nella filosofia che il software deve essere disponibile
gratuitamente; gli strumenti del software devono essere disponibili agli utenti nella loro
lingua madre a prescindere dalle loro abilità e che gli utenti devono avere la libertà di
personalizzare e modificare il software in qualunque modo lo desiderino. Per queste
ragioni:
9
Ubuntu non sarà mai a pagamento e non c'è nessun extra per alcuna «enterprise
edition», il miglior lavoro sarà sempre disponibile a tutti, agli stessi termini gratuiti.
9
Ubuntu comprende le migliori traduzioni e strutture d'accesso che la comunità del
software libero possa offrire, al fine di renderlo utilizzabile dal maggior numero di
utenti possibile.
9
Ubuntu è rilasciato regolarmente a scadenze previste; una nuova versione è
rilasciata ogni 6 mesi. È possibile scegliere di usare la versione stabile o di
sviluppo. Ogni edizione è supportata per almeno 18 mesi.
9
Ubuntu è votata completamente ai principi del software libero e open source; gli
utenti sono incoraggiati all'uso, al miglioramento e alla diffusione del software
libero e open source.
Ci sono molti sistemi operativi diversi basati su Linux: Debian, SuSE, Gentoo, RedHat e
Mandriva sono degli esempi. Ubuntu è un altro contendente in quello che è già un campo
altamente competitivo. Quindi, cosa rende Ubuntu differente?
Basato su Debian, una delle più acclamate, tecnologicamente avanzate e meglio supportate
distribuzioni, cerca di creare una distribuzione che fornisca un ambiente Linux aggiornato
e coerente sia per l'ambiente desktop sia per l'ambiente server. Ubuntu comprende molti
pacchetti selezionati direttamente dalla distribuzione Debian e mantiene il suo software per
72
la gestione dei pacchetti che consente di installare e rimuovere facilmente i programmi.
Diversamente da molte distribuzioni che comprendono una grande quantità di software che
può o non può essere utile, comprende una lista ridotta di programmi, ma di alta qualità e
importanza.
Concentrandosi sulla qualità, Ubuntu fornisce un ambiente solido e ricco di funzionalità
che può essere utilizzato sia in ambito domestico sia in ambienti commerciali. Il progetto si
prende i tempi necessari per migliorare anche i più piccoli dettagli ed è in grado di
rilasciare una nuova versione che incorpori i più aggiornati programmi ogni 6 mesi.
Ubuntu è disponibile per le architetture i386 (processori 386/486/Pentium(II/III/IV),
Athlon/Duron/Sempron), AMD64 (processori Athlon64, Opteron e i nuovi processori a 64bit Intel) e PowerPC (iBook/Powerbook, G4 e G5).
Ambiente grafico:
Il desktop è ciò che si vede dopo l'accesso al computer ed è ciò che si utilizza per la
gestione e l'avvio delle applicazioni. L'ambiente grafico predefinito di Ubuntu è GNOME,
un'importante suite per il desktop e piattaforma per lo sviluppo per Unix e Linux.
È anche possibile installare gli ambienti grafici KDE e Xfce, con il loro aspetto particolare.
KDE e Xfce sono resi disponibili per Ubuntu attraverso i rispettivi progetti Kubuntu e
Xubuntu. È anche possibile installare una versione di Ubuntu solamente con KDE oppure
con Xfce.
73
5. STRUTTURA MIRO ON RAILS
Come gia detto in precedenza, il sistema Miro on Rails fornisce il servizio di tele
refertazione come risposta alle esigenze diagnostiche. Nel descrivere dettagliatamente
come è stato strutturato il sistema, suddivideremo il progetto in diverse aree. Parleremo
quindi dei vari tipi di utente, che il sistema è in grado di fornire, delle loro funzionalità e
modalità. Le tre figure principali che interagiscono con il sistema sono l’amministratore, il
requester e il dottore. Ogni tipo di utente ha un suo stile grafico che lo differenzia
dall’altro, l’interfaccia utilizzata da Miro on Rails è composta da delle schede diversificate
in base alle funzioni di ciascun utente. La cosa che accomuna ciascun utente è la scheda
iniziale, che serve a scopo informativo per gli utenti alle prime armi, che contiene una
descrizione riassuntiva (diversa per ogni tipo di utente) delle varie funzioni messe a
disposizione.
Successivamente verrà analizzata la sezione “Cartella Clinica” "del paziente e il modo in
cui si è voluta organizzare. Solo nel capitolo successivo, si tratterà invece nel dettaglio la
sezione relativa al “Sistema di Messaggistica” di cui si avvale il sistema per la
comunicazione virtuale tra il personale medico.
Figura 15: logo Miro on rails
74
5.1 Autenticazione
Ogni utente per accedere al sistema deve prima compiere una procedura di autenticazione.
Un esempio di tutti i giorni è la comune procedura di autenticazione che conosciamo come
login, ed è proprio quella utilizzata da Miro on Rails Un sistema di elaborazione,
progettato per essere usato soltanto da utenti autorizzati, deve essere in grado di rilevare ed
escludere i non autorizzati. L'accesso ad esso, dunque, viene garantito solo dopo aver
eseguito con successo una procedura di autenticazione, di solito attraverso una username e
una password personale.
Ecco cosa appare ad un utente che si collega, tramite internet, al servizio di tele
refertazione offerto da Miro on Rails all’indirizzo: http://193.205.130.163/miro/user/login.
Figura 16: form di login
Figura 17: autenticazione non riuscita
75
Occorre inoltre sottolineare che il meccanismo di autenticazione che abbiamo realizzato
presenta un accorgimento che aumenta la sicurezza. Quando un nuovo utente riceve
username e password da un administrator, deve modificare la password al primo accesso.
Al primo log-in, il sistema reindirizza automaticamente l’utente nella pagina di modifica
password. Successivamente l’utente potrà comunque modificare la propria password in
qualunque momento.
Figura 18: modifica password primo accesso
76
5.2 Administrator
L’ Amministratore è un tipo di utente che si differenzia rispetto agli altri sia per il livello di
gestione del sistema sia per quanto riguarda la stabilità e la sicurezza che deve garantire.
Per quanto riguarda l’interfaccia grafica della sua sessione, la home presenta la seguente
struttura:
Figura 19: home administrator
Le funzionalità a cui può accedere un administrator sono fondamentalmente tre:
1) Visualizzare gli ultimi utenti inseriti
2) Inserire un nuovo utente nel database
3) Cancellare un utente dal database
inoltre, sempre nella home, può visualizzare il proprio profilo ed eventualmente modificare
la password.
77
Selezionando il tasto “Last Users” comparirà la lista degli ultimi utenti inseriti e cliccando
su uno di questi utenti apparirà la pagina con il profilo. Inoltre grazie alla struttura ad
albero a sinistra è possibile effettuare una selezione in base al tipo di utente.
Selezionando il tasto “New User” sarà possibile inserire un nuovo utente nel database,
l’administrator visualizzerà la pagina di inserimento dati (figura 19).
Figura 20: inserimento dati nuovo utente
Nella fase di inserimento dati, assume un aspetto molto importante la scelta del tipo di
utente (“User type”). Come si vede dalle figure nella pagina successiva, se si sceglie
“Requester” bisognerà inserire anche le informazioni relative alla struttura ospedaliera a
cui appartiene; se si sceglie “Doctor” si dovrà selezionare anche la specializzazione medica
in quanto i dottori vedranno solo i problemi clinici relativi al proprio ramo specialistico;
infine “Administrator” non avrà bisogno di altre informazioni aggiuntive.
78
Figura 21: scelta “User type”
Un’altra funzionalità messa a disposizione dell’administrator e che solo lui può eseguire, è
la possibilità di cancellare un utente dal database. In verità anche in questo caso ci sono
delle restrizioni in quanto si possono cancellare solo utenti del tipo “Requester” e “Doctor”
e non altri “Administrator”. Un administrator potrà essere cancellato solo se si agisce
direttamente sul database centrale e questo potrà essere fatto solo da un Super
Administrator del tutto trasparente al sistema.
79
Per poter cancellare un utente occorre selezionarlo dalla lista “Last Users” e premere il
tasto “Delete” (vedi figura 23).
Figura 22: elimina utente dal database
In alto a sinistra della home page sono presenti le informazioni dell’utente che si è
autenticato.
Figura 23: informazioni utente
Come si vede dalla figura sopra, compariranno nell’ordine:
9 nome e cognome dell’utente
9 il link a “My Profile” dove c’è il riepilogo delle informazioni personali e la
possibilità di modificare la propria password
9 il link a “Exit” che permette all’utente di uscire dal sistema
80
5.3 Requester
Il Requester è una tipologia di utente a cui viene assegnata come funzione principale la
gestione dei pazienti, quindi un punto cardine per il funzionamento del sistema.
Quello del requester è considerato un ruolo indispensabile per far si che il sistema Miro on
rails fornisca un buon servizio al sistema sanitario. Questo perché tutte le sue funzionalità
sono incentrate verso la figura principale da prendere in considerazione ossia il paziente.
Come accennato nei paragrafi precedenti, le figure che assumeranno questo ruolo,
dovranno essere persone che lavorano presumibilmente nell’ambito sanitario, ad esempio
in ospedali, ambulatori o aree di emergenza e così via. L’obiettivo principale del sistema
Miro on rails è quello di aiutare il servizio sanitario dei Paesi in via di sviluppo, dove la
gestione la qualità e l’efficienza del servizio medico sono più scadenti. Quindi la ricerca di
figure professionali che possano svolgere il compito di requester, sarà da effettuare tra le
varie strutture sanitarie presenti nel territorio. Naturalmente la ricerca di persone
abbastanza competenti in queste zone territoriali non sarà molto facile. E’ anche per questo
motivo che per l’estensione e la comprensione di questo servizio fornito, verranno
organizzate delle visite in queste zone da parte di persone competenti che spiegheranno il
funzionamento del sistema e conseguentemente verrà effettuata l’assegnazione di account
requester a persone che si adoperano in queste strutture sanitarie.
A questo punto il sistema sarà operativo grazie alla presenza di requester che si
occuperanno della gestione dei pazienti legati alle strutture in cui il requester svolge il suo
compito.
Le operazioni principali che un requester è in grado di effettuare sono:
1) registrazione dei pazienti
2) gestione della cartella clinica
3) gestione degli eventuali problemi clinici
81
La home del Requester avrà la seguente struttura:
Figura 24: home Requester
come si vede dalla figura l’interfaccia grafica della home page mostra la lista degli ultimi
clinical problems inseriti. Ogni clinical problem è caratterizzato da:
9 Date open: data e ora di apertura evento
9 Patient: nome e cognome del paziente a cui è associato l’evento
9 State: stato dell’evento che può essere open, reported o request another
9 Last report: data e ora di emissione referto medico
Tramite il tasto “New Patient”, il requester è in grado di inserire nuovi pazienti nel
database del sistema specificando i dati personali richiesti per la registrazione, tra cui ad
esempio le informazioni riguardo la residenza, la struttura ospedaliera in cui è ospitato e
informazioni come telefono o e-mail. A questo punto il nuovo paziente inserito potrà
usufruire del servizio fornito da Miro on rails in caso di eventuali problemi clinici. Il
requester quindi dovrà farsi carico della stato dei pazienti che gestisce, aggiornando di
volta in volta la loro condizione nel sistema, in modo che i medici possano avere a
82
disposizione un insieme di dati aggiornati il più possibile. Una volta che il paziente sarà
inserito nel sistema, si potrà successivamente modificare il suo profilo, ossia apportare dei
cambiamenti alle informazioni personali registrate in partenza. Per esempio, nel caso in cui
un paziente sia deceduto, si potrà modificare il suo profilo registrando la data di decesso.
Figura 25: inserimento dati paziente
In realtà la fase di inserimento di un nuovo paziente passa prima per la ricerca nel
database. Se infatti il paziente è già stato inserito comparirà un link al suo profilo, in caso
contrario comparirà un link alla pagina di inserimento dati.
83
Figura 26: ricerca paziente
Come per gli utenti administrators, anche il requester può visualizzare una lista degli utenti
da lui registrati nel sistema. Da sottolineare il fatto che ogni requester visualizzerà nella
84
propria lista solo ed esclusivamente i pazienti da lui inseriti e quindi si occuperà della loro
gestione; ogni requester avrà perciò solo la responsabilità dei pazienti da lui registrati.
Figura 27: lista pazienti
Selezionando un record della lista, si potrà accedere alla cartella clinica relativa al paziente
in questione. Il requester, una volta entrato nella cartella relativa ad un determinato
paziente, potrà visualizzare il suo profilo ed eventualmente apportare delle modifiche.
Inoltre si occuperà della gestione delle informazioni riguardanti lo stato di salute del
paziente, come ad esempio le allergie da cui è influenzato, informazioni mediche
riguardanti il suo nucleo familiare come ad esempio le patologie presenti in famiglia, le
patologie presenti nell’ individuo e tutte le relative informazioni fisiologiche. Il requester
sarà quindi in grado di gestire completamente i dati dei suoi pazienti, con possibilità di
eventuali aggiunte e modifiche.
Oltre al profilo del paziente e alle varie anamnesi presenti, la cartella clinica del paziente
conterrà anche i problemi clinici. Questa può essere definita la funzione più importante per
il requester, poiché l’obiettivo del sistema è proprio quello di fornire una procedura di
refertazione riguardo ai problemi clinici presenti. Infatti i medici registrati nel sistema
85
avranno proprio il compito di emettere dei referti o dei pareri personali sui problemi clinici
presenti.
Figura 28: cartella clinica
Tramite il tasto “Last Clinical Problem”, il requester sarà in grado di visualizzare tutti i
problemi clinici relativi a tutti i pazienti da lui gestiti. In sostanza ottiene la stessa lista che
si presenta nella home page al momento dell’accesso alla propria sessione di lavoro.
Un problema clinico potrà essere composto da uno o più esami, e l’insieme di questi verrà
considerato come un'unica entità ( l’entità “problema clinico”). Il personale medico fornirà
veri e propri “referti” da allegare al problema clinico di un certo paziente, o più
semplicemente fornirà un parere personale cioè un “messaggio”. In questo modo il
requester, visualizzando la lista vedrà lo stato attuale di un certo problema clinico, si baserà
sugli eventuali interventi effettuati dai medici del sistema e di conseguenza apporterà
eventuali modifiche al problema.
Il valore del campo “stato” è conseguente all’intervento medico che è avvenuto per quel
dato problema e alla gestione apportata dal requester. Gli stati del problema possono
essere:
86
•
Open: se il problema clinico inserito dal requester non ha ricevuto ancora nessun
referto medico. Lo stato permane quindi ad “open” anche se sono arrivati eventuali
messaggi.
•
Reported: se il problema clinico ha ottenuto un referto da un medico.
•
Another request: se il requester richiede una second opinion per il problema clinico in
questione.
•
Closed: se il requester considera chiuso il problema clinico in questione, ossia non ha
bisogno di ulteriori risposte dal personale medico (in questo caso il problema clinico
scomparirà automaticamente dalla lista).
Figura 29: aggiungi problema clinico
Nel momento in cui si visualizza la lista dei problemi clinici presenti nella cartella clinica
di un paziente, è possibile aggiungere un nuovo problema clinico procedendo come
mostrato nella figura 24. Verrà mostrata una pagina dove è possibile inserire tutti i dati
relativi ad un nuovo esame clinico (“New Consultation”).
87
Figura 30: inserimento dati esame clinico
88
Figura 31: upload file diagnostico
Sicuramente l’aspetto più importante in questa fase è l’upload di eventuali file diagnostici
come per esempio un semplice elettrocardiogramma. Questo aspetto rappresenta il punto
cardine dell’intero sistema di telerefertazione, infatti il medico che effettuerà il download
dei file, di natura diagnostica, sarà in grado di rilasciare un referto medico o una second
opinion sul caso clinico pur trovandosi in un tutt’altro luogo.
Un altro aspetto da sottolineare è la facilità con cui il requester può effettuare un esame
clinico, si presuppone infatti che sia un tecnico e non uno specialista. Ha a disposizione
una serie di form già impostate dove deve inserire solo i valori.
Nelle figure seguenti viene riportato l’esempio di “Insert laboratory exam” e la stessa cosa
vale per “Insert ECG”. Se il requester si trova a dover effettuare un esame di laboratorio e
ha gli strumenti adeguati, può continuare l’esame clinico arricchendolo di tutta una serie di
informazioni aggiuntive di cui deve solo seguirne la schematizzazione.
In definitiva possiamo dire con assoluta certezza che Miro on rails mette a disposizione del
requester tutti gli strumenti necessari ad effettuare un esame clinico pressoché completo.
Questo però non è vincolante, in quanto se non si dispone dei mezzi necessari ad effettuare
tutti gli esami, si potrà in ogni caso inserire le sole informazioni di cui si ha conoscenza o
utilizzare il solo meccanismo di upload dei file diagnostici.
89
Figura 32: Insert laboratory exam
90
5.4 Doctor
L’ultima sezione che dobbiamo prendere in considerazione, è la sezione Dottore.
L’obiettivo principale degli utenti appartenenti a questa tipologia, è quello di fornire un
servizio in grado di aiutare i pazienti fornendo un consulto specialistico a distanza. Per far
si che questo possa avvenire, dovrà essere presente un canale di comunicazione tra l’entità
paziente e l’entità dottore. Nel nostro caso specifico, la gestione dei dati clinici dei pazienti
è portata avanti dai requester, il paziente quindi è affidato nelle mani di uno specifico
requester. Per questo motivo il sistema di comunicazione non lega la figura del dottore
esattamente con l’entità paziente, ma con il requester che si occupa della sua gestione, e
che conseguentemente terrà il paziente al corrente di tutti gli aggiornamenti, come per
esempio la presenza di nuove diagnosi legate alle sue problematiche. Tutto questo ci fa
capire l’importanza dell’interconnessione tra le figure requester e il dottore.
Essere in possesso di un account di tipo dottore, implica come requisito una certa
professionalità. Sarà quindi compito del “super administrator” occuparsi dell’assegnazione
di account di tipo dottore, il quale si assumerà la responsabilità del suo operato, pertanto
dovrà fare in modo che questi account vengano assegnati a persone qualificate. Tramite
questa procedura di assegnazione, tutti i dottori che verranno inseriti nel sistema
formeranno il personale medico di Miro on rails. Questi medici verranno selezionati tra le
varie strutture sanitarie che vorranno contribuire al servizio fornito dal nostro sistema.
Quindi il nostro personale medico sarà caratterizzato dalla presenza di molti dottori,
appartenenti a diverse strutture anche molto lontane tra loro.
L’obiettivo sarà quindi quello di far aderire il maggior numero di medici qualificati nelle
più svariate specializzazioni affinchè il servizio offerto sia il più efficiente possibile.
91
Figura 33: home page doctor
Nella home del doctor compare la lista dei clinical problem, ciascun record corrisponde ad
uno specifico problema clinico relativo ad un determinato paziente. I campi della lista
contengono informazioni relative alla data di creazione del problema clinico, il suo stato
(la spiegazione dei vari stati è già stata effettuata nel paragrafo precedente), il nome del
paziente a cui è riferito il problema e il requester che si occupa della sua gestione. In realtà
il dottore non visualizzerà nella lista tutti i problemi clinici presenti nel sistema, questo
dipenderà dalla politica di gestione che si è voluta adottare. Innanzitutto, quando viene
creato un utente di tipo dottore, l’administrator dovrà stabilire per quali specializzazioni il
dottore sarà ritenuto qualificato. Quindi le specializzazioni possedute da un dottore
caratterizzeranno il suo livello di operatività all’interno del sistema, in altre parole, il
dottore riuscirà a visualizzare nella lista in figura, solo i problemi clinici inerenti alle
specializzazioni da lui in possesso.
Come abbiamo detto in precedenza il problema clinico è composto da uno o più esami
clinici, ed è visto come un unico evento. Quindi i referti e i messaggi non saranno legati ai
singoli esami clinici ma all’evento. Quindi potrebbe capitare ad esempio che ci siano
problemi clinici composti da più esami relativi a diverse specializzazioni, un dottore
92
potrebbe quindi possedere o tutte le specializzazioni legate a quel problema clinico o
almeno una di esse o nessuna. La politica di gestione che si è voluta adottare in questo
caso, stabilisce che un dottore potrà visualizzare nella lista solo i problemi clinici che
hanno almeno un esame clinico relativo ad una qualsiasi delle specializzazioni possedute.
Un’altra specifica relativa alla politica di visualizzazione è legata allo stato, i dottori
saranno in grado di visualizzare solo i problemi clinici in stato di “open” o “request
another”. In questo modo si cerca di dare priorità ai problemi che non hanno ottenuto
finora ancora nessun referto medico (stato “open”) e quelli che hanno già ottenuto un
referto, ma che ne richiedono una second opinion (stato “request another”). Gli altri
problemi in stato “reported”o “closed” non compaiono in questa lista. Il fatto di applicare
queste specifiche alla visualizzazione è dovuto al fatto che senza di queste i dottori
avrebbero a che fare con delle liste enormi e quindi difficili da gestire.
Riassumendo, con l’introduzione delle specifiche relative alle specializzazioni e allo stato
dei problemi si effettua un filtraggio, si cerca cioè di limitare il numero di problemi da
visualizzare ed avere una gestione più efficiente da parte dei medici.
Quando verrà selezionato dalla lista un determinato problema clinico, in automatico verrà
aperta la Cartella Clinica del relativo paziente. Il dottore avrà non solo la possibilità di
esaminare il problema clinico che ha selezionato, ma anche tutti gli altri relativi allo stesso
paziente. In questo modo avrà una visione globale dello stato del paziente e sarà più facile
emettere referti o semplici pareri.
Anche il dottore come il requester, è in grado di accedere alla cartella clinica dei pazienti,
anche se le funzioni che potrà svolgere sono diverse. Il dottore sarà in grado di
visualizzare i problemi clinici e le informazioni personali dei pazienti ed inoltre, cosa più
importante, sarà in grado di fornire delle risposte alle problemi clinici tramite referti o
semplici pareri personali.
Le funzioni fondamentali che può utilizzare un dottore sono:
1) Add report: aggiunta di un referto medico
2) Add message: aggiunta di un parere medico
93
Figura 34: Add report e Add message
Un aspetto molto importante è che il dottore può fare il download, sul proprio computer, di
eventuali file allegati al problema clinico. In questo modo può avere una situazione ancora
più dettagliata del caso clinico.
Figura 35: file di natura diagnostica
In figura è mostrato un esempio con due allegati (“Attachments”). Cliccando su uno dei
due file è possibile salvarlo sul proprio PC.
94
Figura 36: salva allegato
5.5 Sezione messaggi
Un’area importante che caratterizza il portale Miro on rails è quella incentrata sullo
scambio di messaggi da parte dei dottori. In questo modo il personale medico del sistema
sarà in grado di fornire delle risposte più precise e di confrontarsi su specifici problemi
clinici.
Figura 37: Last topics
95
Nella figura si vede che il dottore può visualizzare la lista degli ultimi messaggi e
selezionando un record dalla lista può leggere un messaggio relativo ad uno specifico
problema clinico.
Figura 38: esempio messaggio
Il messaggio è accompagnato da una serie di informazioni come:
9 Message cod.: codice identificativo del messaggio
9 data e ora di inserimento messaggio
9 nome del dottore e link al suo profilo
Figura 39: operazioni “Add message” e “Close”
96
Sul messaggio si possono compiere due operazioni: “Add message” con la quale si
aggiunge un messaggio ad uno specifico problema clinico e “Close” con la quale si chiude
il messaggio e si ritorna alla lista iniziale.
97
6. CONCLUSIONI E SVILUPPI FUTURI
6.1 Conclusioni
Lo scopo del progetto, era quello di creare una struttura software flessibile che offrisse
servizi di telerefertazione distinguendo in modo netto la fase di effettuazione dell’esame
dalla fase di refertazione. L’architettura che è stata realizzata è in grado di fornire un valido
supporto anche per altri servizi tipici di applicazioni di telemedicina come la consultazione
della cartella clinica on-line.
Un aspetto importante del progetto è stato sicuramente l’utilizzo del framework Ruby on
rails, la scelta è stata dettata dalla fama che in questi anni ha ottenuto Rails nello sviluppo
di applicazioni web al pari di altri framework più consolidati scritti in Java. Questa scelta
ci ha dato la possibilità di rilevare interessanti aspetti di confronto con altre tecnologie.
Utilizzando Ruby on rails siamo arrivati alla conclusione che il termine più adatto per
definire il suo punto di forza è la “produttività”. In molti casi la produttività è il fattore più
importante nello sviluppo di un software, se il proprio progetto deve essere enfatizzato per
qualità, disponibilità e performance, la produttività è la chiave per ottenere ciò.
Con una maggiore produttività si ha quindi più tempo per concentrarsi sul miglioramento
delle caratteristiche dell’applicazione.
Un altro aspetto fondamentale ha riguardato la verifica del corretto funzionamento
dell’applicazione Miro on Rails e della sua usabilità, occorre infatti ricordare che
l’applicazione è rivolta a molte tipologie di utenti: dottori, personale tecnico sanitario,
missionari e utenti senza alcuna competenza specifica. Abbiamo avuto la possibilità di
testare il sistema utilizzando come server centrale una macchina del dipartimento DEIT
(Dipartimento di Elettronica Intelligenza Artificiale e Telecomunicazioni) della facoltà di
ingegneria
di
Ancona.
Il
sistema
è
attualmente
on-line
all’indirizzo
http://193.205.130.163/miro/user/login. In questa fase abbiamo coinvolto una piccola
comunità di medici e tecnici del settore affinchè utilizzassero l’applicazione e ci
informassero di tutti i miglioramenti possibili.
In conclusione possiamo dire con assoluta certezza che il sistema realizzato è stabile ed
efficiente anche se ci sono numerosi sviluppi da portare avanti.
98
6.2 Sviluppi futuri
Nonostante il portale Miro on rails sia stabile, ben organizzato ed efficiente dal punto di
vista delle funzionalità, ci possono essere numerosi spunti per sviluppi futuri.
In questa sezione vorremmo focalizzare l’attenzione su quattro possibili sviluppi che in
futuro potrebbero migliorare le funzionalità di base dell’applicazione.
1) download e upload più interattivi con possibilità di resume: attualmente se la
connessione cade durante l’upload (o un download) di un file diagnostico, bisogna
ripetere l’operazione dall’inizio. Sarebbe più efficiente prevedere un protocollo di
resume che permetta di riprendere l’operazione laddove è stata interrotta.
2) possibilità per il requester di lavorare off-line: se il requester si trova in zone senza
collegamento internet ma riesce ad effettuare un esame clinico, dovrebbe salvare tutti i
dati da qualche parte per poi ricopiare il tutto sul portale quando raggiunge una zona
con connessione. Si trova quindi a dover compiere due volte le stesse operazioni.
Molto più vantaggioso sarebbe progettare una plugin che renda il portale visibile in
locale, poi quando ci si connette ad internet tutte le informazioni in locale verrebbero
automaticamente inviate al server.
3) meccanismo di timestamping per problemi di tipo legale tra dottore e requester:
supponiamo che il requester inserisca un certo problema clinico e che successivamente
il dottore visualizzi tale problema ed emetta un referto medico. Potrebbe succedere che
il requester abbia tralasciato informazioni importanti e che li aggiunga al problema in
questione successivamente dopo l’arrivo del referto. Data la mancanza di alcuni dati, il
dottore potrebbe aver sbagliato la sua diagnosi. Nel caso in cui tale referto provochi
danni al paziente, il dottore potrebbe essere perseguibile legalmente. Utilizzando
invece il meccanismo di timestamping verrà registrata la data e l’ora per ogni
operazione di inserimento, cancellazione e modifica sui dati. In questo caso, il
requester, potrebbe verificare se il referto è arrivato prima dell’inserimento degli esami
clinici mancanti.
4) meccanismo di firma digitale con smart card per i dottori
99
5) servizi disponibili direttamente al paziente: l’obiettivo futuro sarà sfruttare la grande
flessibilità con sui è stato progettato Miro on rails, espandendo le sue funzionalità per poter
raggiungere direttamente gli utenti finali, i pazienti, in modo da rendere il servizio sanitario
efficiente e capillare.
100
Appendice A: CONTROLLERS
# Filters added to this controller apply to all controllers in the
application.
# Likewise, all the methods added will be available for all controllers.
class ApplicationController < ActionController::Base
layout "layout"
# Pick a unique cookie name to distinguish our session data from
others'
session :session_key => '_tesi_session_id'
def init
@root_directory= "/miro"
@user_logged=is_logged
redirect_to(:controller=>:user,:action=>:login) unless @user_logged
end
def is_logged
if session
if session[:user_id]
user=User.find(:first,:conditions=>["id= ? ",session[:user_id]])
return user
elsif cookies[:user_id]!=nil
user=User.validate_login_with_cookie(cookies[:user_id],cookies[:user_pass
word])
if user
session[:user_id] = user.id
return user
end
end
end
nil
end
def get_cities
@cities=City.find(:all,:conditions=>["province_id=?",params[:province_id]
],:order=>"name")
@province_name=Province.find(:first,:conditions=>["id=?",params[:province
_id]]).name
render
:text=>'<label
for="'+params[:tag]+'_city"
class="DetailTitle">City</label><br
/><select
name="'+params[:tag]+'city_id"
id="'+params[:tag]+'city_id"
class="UserTextFieldHalf">'+
render_to_string(:partial
=>
"/city_options",:collection=>@cities)+"</select>"
end
def get_provinces
@provinces=Province.find(:all,:conditions=>["country_id=?",params[:countr
y_id]],:order=>"name")
render
:text=>'<label
for="'+params[:tag]+'provinces"
class="DetailTitle">Province:</label><br
/><select
101
name="place['+params[:tag]+'province_id]"
id="'+params[:tag]+'province_id" class="UserTextFieldHalf" >'+
"<option value=''>Province</option>"+render_to_string(:partial
=> "/province_options",:collection=>@provinces)+"</select>"+
"<script>document.getElementById('"+params[:tag]+"province_id').onchange=
function(){new
Ajax.Updater('"+params[:tag]+"city_idDiv',
'/miro/index/get_cities',
{asynchronous:true,
evalScripts:true,
parameters:'tag="+params[:tag]+"&province_id='+this.value});return
false;}</script>"
end
def get_visit_body
init
render
:partial=>"/patient/view_visit",:object=>Visit.find(:first,:conditions=>[
"id=?",params[:id]])
end
def get_reports_body
init
render
:partial=>"/view_report",:object=>Report.find(:all,:conditions=>["event_i
d=?",params[:id]],:order=>"id desc")
end
def get_topic_body
init
render
:partial=>"/view_message",:object=>Forum.find(:all,:conditions=>["event_i
d=?",params[:id]],:order=>"id desc")
end
def get_form_allergology
@form=params[:new] ? "new" : "edit"
@anamnesis_allergology=params[:new] ?
AnamnesisAllergology.find(params[:id])
render :partial=>"fields_allergology"
end
def get_form_family
@form=params[:new] ? "new" : "edit"
@anamnesis_familiar=params[:new]
?
AnamnesisFamiliar.find(params[:id])
render :partial=>"fields_familiar"
end
AnamnesisAllergology.new
:
AnamnesisFamiliar.new
:
def get_form_family_pathology
@form=params[:new] ? "new" : "edit"
@anamnesis_family_pathology=params[:new]
?
AnamnesisFamilyPathology.new : AnamnesisFamilyPathology.find(params[:id])
render :partial=>"fields_family_pathology"
end
def get_form_pathological
@form=params[:new] ? "new" : "edit"
@anamnesis_pathological=params[:new] ? AnamnesisPathological.new :
AnamnesisPathological.find(params[:id])
102
render :partial=>"fields_pathological"
end
def get_form_physiological
@form=params[:new] ? "new" : "edit"
@anamnesis_physiological=params[:new] ? AnamnesisPhysiological.new
: AnamnesisPhysiological.find(params[:id])
render :partial=>"fields_physiological"
end
def get_form_visit
@form="new" #params[:new] ? "new" : "edit"
@visit=Visit.new
#params[:new]
Visit.find(params[:id])
render :partial=>"fields_visit"
end
?
Visit.new
:
def get_form_info
@form="edit"
@patient=Patient.find(:first,:conditions=>["id=?",params[:id]])
render :partial=>"fields_info"
end
def get_edit_form_familiar
@form="edit"
@anamnesis_familiar=AnamnesisFamiliar.find(:first,:conditions=>["patient_
id=?",params[:id]])
render :partial=>"fields_familiar"
end
def get_edit_form_physiological
@form="edit"
@anamnesis_physiological=AnamnesisPhysiological.find(:first,:conditions=>
["patient_id=?",params[:id]])
render :partial=>"fields_physiological"
end
def get_edit_form_allergology
@form="edit"
@anamnesis_allergology=AnamnesisAllergology.find(:first,:conditions=>["id
=?",params[:id]])
render :partial=>"fields_allergology"
end
def get_edit_form_family_pathology
@form="edit"
@anamnesis_family_pathology=AnamnesisFamilyPathology.find(:first,:conditi
ons=>["id=?",params[:id]])
render :partial=>"fields_family_pathology"
end
def get_edit_form_pathological
@form="edit"
103
@anamnesis_pathological=AnamnesisPathological.find(:first,:conditions=>["
id=?",params[:id]])
render :partial=>"fields_pathological"
end
def get_city
city=GeoKit::Geocoders::GoogleGeocoder.geocode(params[:place_city])
render :text => city.precision=="city" ? city.full_address : ""
end
def set_city(city_s)
city=Location.find(:first,:conditions=>["full_address=?",city_s])
if city
return city.id
else
city=GeoKit::Geocoders::GoogleGeocoder.geocode(city_s)
if city
loc=Location.new
loc.lat=city.lat
loc.lng=city.lng
loc.country_code=city.country_code
loc.full_address=city.full_address
loc.precision=city.precision
loc.city=city.city
loc.state=city.state
loc.save
return loc.id
else
return nil
end
end
end
end
class DoctorController < ApplicationController
def get_exam_file
init
if @user_logged and @user_logged.class.to_s=="Doctor"
@exam_file=ExamFile.find(:first,:conditions=>["id=?",params[:id]])
send_file @exam_file.get_filename if @exam_file
end
end
def new_report
init
if @user_logged.class.to_s=="Doctor"
@page_body="fields_report"
@page_title="New Report"
@form="new"
@report=Report.new
if request.post?
104
@report=Report.new(params[:report])
@report.user_id=@user_logged.id
@report.event_id=params[:id]
@report.created_at=Time.now
[email protected]
if @report.save
event.state="reported"
event.save
end
render
:partial=>"/view_report",:collection=>Report.find(:all,:conditions=>["eve
nt_id=?",event.id])
#redirect_to(:controller=>:patient,:action=>:view,:id=>event.patient_id,:
section=>"visits")
end
else
redirect_to(:controller=>:doctor,:action=>:permission_denied)
end
end
def new_message
init
if @user_logged.class.to_s=="Doctor"
#@page_body="fields_message"
@page_title="New Message"
@form="new"
@forum=Forum.new
if request.post?
@forum=Forum.new(params[:forum])
@forum.user_id=@user_logged.id
@forum.event_id=params[:id]
@forum.save
render
:partial=>"/view_message",:collection=>Forum.find(:all,:conditions=>["eve
nt_id=?",@forum.event_id])
end
else
redirect_to(:controller=>:doctor,:action=>:permission_denied)
end
end
def get_form_report
init
if @user_logged.class.to_s=="Doctor"
@report=Report.new
render (:partial=>'fields_report', :object=>params[:id])
end
end
def get_form_message
init
if @user_logged.class.to_s=="Doctor"
@report=Report.new
render (:partial=>'fields_message', :object=>params[:id])
end
end
105
end
class IndexController < ApplicationController
def index
init
@page_body="index"
@page_title="Home"
@page="index"
#@reports=Report.find(:all,:include=>{:event=>:user},:conditions=>"user=?
"+@user_logged.id)
if @user_logged
if(@user_logged.type.to_s=="Administrator")
@users=User.find(:all,:conditions=>"creator_id=#{@user_logged.id}",:order
=>"id desc")
elsif(@user_logged.type.to_s=="Doctor")
@events_specialization=Event.find(:all,
:include=>:patient,
:joins=>"right join visits on events.id=visits.event_id and
visits.exam_id
in
(select
exam_id
from
exams_users
where
exams_users.user_id=#{@user_logged.id})",
:conditions=>"events.state<>'close' and events.state<>'reported'
and events.user_id<>#{@user_logged.id}",
:order=>"events.id")
else
@events=Event.find(:all,:conditions=>"events.state<>'close' and
user_id=#{@user_logged.id}",:order=>"id desc")
end
end
end
def get_events_specialization
init
@events_specialization=Event.find(:all,
:include=>:patient,
:joins=>"right
join
visits
on
events.id=visits.event_id
and
visits.exam_id
in
(select
exam_id
from
exams_users
where
exams_users.user_id=#{@user_logged.id})",
:conditions=>"events.state<>'close'
and
events.state<>'reported'
and events.user_id<>#{@user_logged.id}",
:order=>"events.id") if @user_logged
render :partial=>"/index/events_specialization"
end
def get_last_events
init
@events=Event.find(:all,:conditions=>"events.state<>'close'
user_id=#{@user_logged.id}",:order=>"id desc")
render :partial=>"/index/last_events"
end
and
106
def get_last_users
init
@users=User.find(:all,:conditions=>["creator_id=#{@user_logged.id}
and type like ?",(params[:type] ? params[:type] : '%')],:order=>"id
desc") if @user_logged
render :partial=>"/index/last_users"
end
def get_last_topics
init
@topics=Forum.find(:all,:include=>[:event],:conditions=>"forums.user_id=#
{@user_logged.id}",:order=>"forums.id desc") if @user_logged
render :partial=>"/index/last_topics"
end
def get_last_patients
init
@patients=Patient.find(:all,:conditions=>"user_id=#{@user_logged.id}",:or
der=>"id desc") if @user_logged
render :partial=>"/index/last_patients"
end
end
class PatientController < ApplicationController
#upload_status_for :new_visit
def new
init
@page_body="fields_info"
@page_title="New Patient"
@form="new"
@patient=Patient.new
if request.post?
@patient=Patient.new(params[:patient])
@patient.born_location_id=set_city(params[:born])
@patient.residence_location_id=set_city(params[:residence])
params[:residence]
@patient.user_id=session[:user_id]
if @patient.save
@page="new_patient"
if
redirect_to({:controller=>:patient,:action=>:view,:id=>@patient.id,:secti
on=>"info"})
else
@page="new_patient"
render :partial=>"/patient/fields_info"
end
end
end
def search
107
init
list=""
if (params[:name] and params[:surname] and params[:born_date])
@patients=Patient.find(:all,:include=>:born_location,:conditions=>"name
like \"#{params[:name]}\" and surname like \"#{params[:surname]}\" and
born_date=\"#{Date.parse(params[:born_date])}\" #{params[:born_city] and
params[:born_city]!=""
?
"and
locations.full_address=\"#{params[:born_city]}\" " : ""}")
for i in @patients
list+="<a
href='#{@root_directory}/patient/view/#{i.id}?section=info'>#{i.id}
#{i.residence_address}
#{i.residence_location_id
?
i.residence_location.full_address : ""}</a>"
end
list="" if @patients.length==0
end
render :text=>list
end
def view
init
@page_body="view"
@patient=params[:id]
?
Patient.find(:first,:include=>[{:anamnesis_family_pathologies=>:pathology
},{:anamnesis_allergologies=>:allergy},:born_location,:residence_location
],:conditions=>["patients.id=?",params[:id]]) : Patient.new
@form="new"
case params[:section]
when "info"
if @patient.id
@partial_view="view_info"
else
@page="new_patient"
@partial_view="fields_info"
end
when "allergology"
@partial_view=(@patient.anamnesis_allergologies.length>0
or
@user_logged.class.to_s!="Requester")
?
"view_allergologies"
:
"fields_allergology"
when "familiar"
@partial_view=(@patient.anamnesis_familiar
or
@user_logged.class.to_s!="Requester")
?
"view_familiar"
:
"fields_familiar"
when "family_pathologies"
@partial_view=(@patient.anamnesis_family_pathologies.length>0 or
@user_logged.class.to_s!="Requester")
?
"view_family_pathologies"
:
"fields_family_pathology"
when "pathologicals"
@partial_view=(@patient.anamnesis_pathologicals.length>0
or
@user_logged.class.to_s!="Requester")
?
"view_pathologicals"
:
"fields_pathological"
when "physiological"
@partial_view=(@patient.anamnesis_physiological
or
@user_logged.class.to_s!="Requester")
?
"view_physiological"
:
"fields_physiological"
when "visits"
@partial_view=(@patient.events.length>0
or
@user_logged.class.to_s!="Requester") ? "view_visits" : "fields_visit"
108
end
@[email protected]
?
#{@patient.surname}" : "New Patient"
@page_body=@partial_view
end
"Patient:
#{@patient.name}
def get_informations
init
@page_body="view"
if not params[:event_id]
@patient=if params[:id]
p=Patient.find(params[:id])
if p.events.size>0
c=Patient.find(:first,:include=>[:events,{:anamnesis_family_pathologies=>
:pathology},{:anamnesis_allergologies=>:allergy},:born_location,:residenc
e_location],:conditions=>["events.state<>'close'
and
patients.id=?",params[:id]])
end
c ? c : p
else
Patient.new
end
else
@patient=Patient.find(:first,
:include=>{:events=>:visits},
:conditions=>["visits.exam_id in (select exam_id from exams_users
where
exams_users.user_id=#{@user_logged.id})
and
events.id=?",params[:event_id]])
end
@form="new"
case params[:section]
when "info"
if @patient.id
@partial_view="view_info"
else
@page="new_patient"
@partial_view="fields_info"
end
when "allergology"
@partial_view=(@patient.anamnesis_allergologies.length>0
or
@user_logged.class.to_s!="Requester")
?
"view_allergologies"
:
"fields_allergology"
when "familiar"
@partial_view=(@patient.anamnesis_familiar
or
@user_logged.class.to_s!="Requester")
?
"view_familiar"
:
"fields_familiar"
when "family_pathologies"
@partial_view=(@patient.anamnesis_family_pathologies.length>0 or
@user_logged.class.to_s!="Requester")
?
"view_family_pathologies"
:
"fields_family_pathology"
when "pathologicals"
@partial_view=(@patient.anamnesis_pathologicals.length>0
or
@user_logged.class.to_s!="Requester")
?
"view_pathologicals"
:
"fields_pathological"
when "physiological"
109
@partial_view=(@patient.anamnesis_physiological
or
@user_logged.class.to_s!="Requester")
?
"view_physiological"
:
"fields_physiological"
when "visits"
@partial_view=(@patient.events.length>0
or
@user_logged.class.to_s!="Requester") ? "view_visits" : "fields_visit"
end
render :partial =>@partial_view
end
def new_visit
init
@page_body="fields_visit"
@page_title="New Visit"
@form="new"
@visit=Visit.new
@ecg=Ecg.new
@laboratory_exam=LaboratoryExam.new
if request.post?
@visit=Visit.new(params[:visit])
@visit.visit_date=Time.now
@visit.patient_id=params[:id]
@visit.user_id=session[:user_id]
@visit.laboratory_exam=LaboratoryExam.new(params[:laboratory_exam])
if params[:data_laboratory_exam]
@visit.ecg=Ecg.new(params[:ecg]) if params[:data_ecg]
if params[:event_id]
@visit.event_id=params[:event_id]
else
@event=Event.new(:user_id=>session[:user_id],:patient_id=>params[:id])
@event.state="open"
@event.created_at=Time.now
@visit.event=@event
end
j=0
for i in 0..(params[:visit][:exam_file].size-1)
if params[:visit][:exam_file][i.to_s][:uploaded_data]!=""
#ExamFile.create(params[:visit][:exam_file][i.to_s])
@visit.exam_files[j]=ExamFile.new(params[:visit][:exam_file][i.to_s])
j+=1
end
end
if @visit.event and @visit.save
redirect_to(:controller=>:patient,:action=>:view,:id=>params[:id],:sectio
n=>"visits")
else
render(:controller=>:patient,:action=>:new)
end
end
end
def new_allergology
init
@page_body="fields_allergology"
@page_title="New allergology"
110
@form="new"
@allergology=AnamnesisAllergology.new
if request.post?
@allergology=AnamnesisAllergology.new(params[:anamnesis_allergology])
@allergology.patient_id=params[:id]
@[email protected]
if @allergology.save
render :partial =>'view_allergologies'
else
render :partial =>'fields_allergology'
end
end
end
def new_familiar
init
@page_body="fields_familiar"
@page_title="New Familar"
@form="new"
@anamnesis_familiar=AnamnesisFamiliar.new
if request.post?
@anamnesis_familiar=AnamnesisFamiliar.new(params[:anamnesis_familiar])
@anamnesis_familiar.patient_id=params[:id]
@patient=@anamnesis_familiar.patient
if @anamnesis_familiar.save
render :partial=>"/patient/view_familiar"
#redirect_to(:controller=>:patient,:action=>:view,:id=>params[:id],:secti
on=>"familiar")
else
render :partial=>"/patient/fields_familiar"
#render(:controller=>:patient,:action=>:new)
end
end
end
def new_pathological
init
@page_body="fields_pathological"
@page_title="New anamnesis pathological"
@form="new"
@anamnesis_pathological=AnamnesisPathological.new
if request.post?
@anamnesis_pathological=AnamnesisPathological.new(params[:anamnesis_patho
logical])
@anamnesis_pathological.patient_id=params[:id]
@anamnesis_pathological.location_id=set_city(params[:pathological])
@patient=@anamnesis_pathological.patient
if @anamnesis_pathological.save
render :partial=>"/patient/view_pathologicals"
#redirect_to(:controller=>:patient,:action=>:view,:id=>params[:id],:secti
on=>"pathologicals")
else
render :partial=>"/patient/fields_pathological"
111
#render(:controller=>:patient,:action=>:new)
end
end
end
def new_family_pathology
init
@page_body="fields_family_pathology"
@page_title="New anamnesis family pathology"
@form="new"
@anamnesis_family_pathology=AnamnesisFamilyPathology.new
if request.post?
@anamnesis_family_pathology=AnamnesisFamilyPathology.new(params[:anamnesi
s_family_pathology])
@anamnesis_family_pathology.patient_id=params[:id]
if @anamnesis_family_pathology.save
@patient=@anamnesis_family_pathology.patient
render :partial =>'/patient/view_family_pathologies'
else
# render :partial=>"/patient/fields_family_pathology"
render :partial =>'/patient/fields_family_pathology'
#render(:controller=>:patient,:action=>:new)
end
end
end
def new_physiological
init
@page_body="fields_physiological"
@page_title="New anamnesis physiological"
@form="new"
@anamnesis_physiological=AnamnesisPhysiological.new
if request.post?
@anamnesis_physiological=AnamnesisPhysiological.new(params[:anamnesis_phy
siological])
@anamnesis_physiological.patient_id=params[:id]
if @anamnesis_physiological.save
@patient=@anamnesis_physiological.patient
render :partial=>"/patient/view_physiological"
#redirect_to(:controller=>:patient,:action=>:view,:id=>params[:id],:secti
on=>"physiological")
else
render :partial=>"/patient/fields_physiological"
#render(:controller=>:patient,:action=>:new)
end
end
end
def edit
init
@patient=Patient.find(:first,:conditions=>"patients.id=#{params[:id]}")
if params[:id]
112
@anamnesis_allergology=AnamnesisAllergology.find(:first,:conditions=>"pat
ient_id=#{params[:id]}") if params[:section]=="allergology"
@anamnesis_familiar=AnamnesisFamiliar.find(:first,:conditions=>"patient_i
d=#{params[:id]}") if params[:section]=="familiar"
@anamnesis_family_pathology=AnamnesisFamilyPathology.find(:first,:conditi
ons=>"patient_id=#{params[:id]}") if params[:section]=="family_pathology"
@anamnesis_pathological=AnamnesisPathological.find(:first,:conditions=>"p
atient_id=#{params[:id]}") if params[:section]=="pathological"
@anamnesis_physiological=AnamnesisPhysiological.find(:first,:conditions=>
"patient_id=#{params[:id]}") if params[:section]=="physiological"
@page_body="edit"
@form="edit"
end
def edit_info
init
@patient=Patient.find(:first,:conditions=>"patients.id=#{params[:id]}")
if params[:id]
@page_body="edit"
@form="edit"
if request.post?
@patient.born_location_id=set_city(params[:born])
@patient.residence_location_id=set_city(params[:residence])
if
params[:residence]
if @patient.update_attributes(params[:patient])
render :partial=>"/patient/view_info"
else
render :partial=>"/patient/fields_info"
end
end
end
def edit_allergology
init
@page_body="edit"
@form="edit"
if request.post?
@anamnesis_allergology=AnamnesisAllergology.find(:first,:conditions=>["id
=?",params[:id]])
if
@anamnesis_allergology.update_attributes(params[:anamnesis_allergology])
@patient=@anamnesis_allergology.patient
render :partial=>"/patient/view_allergologies"
#redirect_to(:controller=>:patient,:action=>:view,:id=>@anamnesis_allergo
logy.patient_id,:section=>"allergology")
else
render :partial=>"/patient/fields_allergology"
end
end
end
113
def edit_familiar
init
@page_body="edit"
@form="edit"
if request.post?
@anamnesis_familiar=AnamnesisFamiliar.find(:first,:conditions=>["id=?",pa
rams[:id]])
@patient=@anamnesis_familiar.patient
if
@anamnesis_familiar.update_attributes(params[:anamnesis_familiar])
render :partial=>"/patient/view_familiar"
#redirect_to(:controller=>:patient,:action=>:view,:id=>@anamnesis_familia
r.patient_id,:section=>"familiar")
else
render :partial=>"/patient/edit_familiar"
end
end
end
def edit_family_pathology
init
@page_body="edit"
@form="edit"
if request.post?
@anamnesis_family_pathology=AnamnesisFamilyPathology.find(:first,:conditi
ons=>["id=?",params[:id]])
if
@anamnesis_family_pathology.update_attributes(params[:anamnesis_family_pa
thology])
@patient=@anamnesis_family_pathology.patient
render :partial=>"/patient/view_family_pathologies"
else
render :partial=>"/patient/fields_family_pathology"
end
end
end
def edit_pathological
init
@page_body="edit"
@form="edit"
if request.post?
@anamnesis_pathological=AnamnesisPathological.find(:first,:conditions=>"i
d=#{params[:id]}")
#@anamnesis_pathological.city_id=params[:city_id].to_i
if
params[:city_id]
@anamnesis_pathological.location_id=set_city(params[:pathological])
if
params[:pathological]
if
@anamnesis_pathological.update_attributes(params[:anamnesis_pathological]
)
render
:partial=>"/patient/view_pathological",:object=>@anamnesis_pathological
114
#redirect_to(:controller=>:patient,:action=>:view,:id=>@anamnesis_patholo
gical.patient_id,:section=>"pathologicals")
else
render :partial=>"/patient/fields_pathological"
end
end
end
def edit_physiological
init
@page_body="edit"
@form="edit"
if request.post?
@anamnesis_physiological=AnamnesisPhysiological.find(:first,:conditions=>
"id=#{params[:id]}")
if
@anamnesis_physiological.update_attributes(params[:anamnesis_physiologica
l])
@patient=@anamnesis_physiological.patient
render
:partial=>"/patient/view_physiological",:object=>@anamnesis_physiological
#redirect_to(:controller=>:patient,:action=>:view,:id=>@anamnesis_physiol
ogical.patient_id,:section=>"physiological")
else
render :partial=>"/patient/fields_physiological"
end
end
end
def close_event
init
event=Event.find(params[:id])
event.state="close"
event.closed_at=Date.today
event.save
redirect_to(:controller=>:patient,:action=>:view,:id=>event.patient_id,:s
ection=>"visits")
end
def request_second_opinion
init
event=Event.find(params[:id])
event.state="request another"
event.save
redirect_to(:controller=>:patient,:action=>:view,:id=>event.patient_id,:s
ection=>"visits")
end
def change_event_state
init
event=Event.find(params[:event_id])
event.state=params[:state]
event.closed_at=Time.now if params[:state]=="close"
event.save
115
@page_body="view"
@patient=Patient.find(:first,:include=>[{:anamnesis_family_pathologies=>:
pathology},{:anamnesis_allergologies=>:allergy},:born_location,:residence
_location],:conditions=>["patients.id=?",event.patient_id])
render :partial=>"/patient/view_visits"
end
def get_form_patient
init
@page_body="fields_info"
@page_title="New Patient"
@form="new"
@patient=Patient.new
render :partial=> "/patient/fields_info"
end
def get_anamnesi_allergology
render
:partial
=>
"/patient/view_allergology",
:object=>AnamnesisAllergology.find(:first,:conditions=>["id=?",params[:id
]])
end
def get_anamnesi_family_pathology
render
:partial
=>
"/patient/view_family_pathology",
:object=>AnamnesisFamilyPathology.find(:first,:conditions=>["id=?",params
[:id]])
end
def get_anamnesi_pathological
render
:partial
=>
"/patient/view_pathological",
:object=>AnamnesisPathological.find(:first,:conditions=>["id=?",params[:i
d]])
end
end
class UserController < ApplicationController
def new
init
@no_submenu=1
if(@user_logged and @user_logged.class.to_s=='Administrator')
@page_body="form"
@page_title="New User"
@page="new_user"
@form="new"
@user=User.new
if request.post?
@user=User.new(params[:user])
@user.location_id=set_city(params[:location])
params[:location]
@user.creator_id=session[:user_id]
#@user.city_id=params[:city_id]
@user.type=params[:user][:type]
if params[:exams]
@exams=Exam.find(params[:exams])
if
116
@user.exams=@exams
end
if @user.save
flash[:notice] = "Registration Complete!"
#Inserire procedura per inviare l'email con i dati utente
redirect_to(:controller=>:user,:action=>:view,:id=>@user.id)
else
render(:controller=>:user,:action=>:new)
end
end
elsif(not @user_logged)
redirect_to(:action=>:login)
else
render :text=>@user_logged.type.to_s
end
end
def edit
init
@page_body="form"
@page_title="Edit User"
@page="edit_user"
@form="edit"
@user=User.new
if params[:id] and request.post?
@user=User.find(:first,:conditions=>["id=?",params[:id]])
@user.password=params[:user][:password]
@user.first_login=0
if @user.save
page="view"
end
redirect_to(:controller=>:user,:action=>(page
?
page
"edit"),:id=>params[:id])
end
:
end
def permission_denied
init
end
def mail_sent
@page_title="Registration complete"
@page_body="mail_sent"
end
def login
@page_body="login"
@page_title="Login"
if @user_logged
redirect_to(:controller => "index")
else
if request.post?
session[:user_id] = nil
@user=User.new(params[:user])
[email protected]_login
if user
session[:user_id] = user.id
117
if params[:user]['enable_cookie']=="1"
cookies[:user_id] = { :value
=> user.id.to_s, :expires
=> 30.days.from_now }
cookies[:user_password]
=
{
:value
=>
user.hashed_password, :expires => 30.days.from_now }
end
if user.first_login==1
redirect_to(:controller => :user,:action=>:view,:id=>user.id)
else
redirect_to(:controller => "index")
end
else
flash[:notice] = "Invalid user/password combination"
end
end
end
end
def logout
session[:user_id] = nil
cookies.delete :user_id
cookies.delete :user_password
flash[:notice] = "Logged out"
redirect_to(:controller => "user",:action=>"login")
end
def view
init
@page_body="view"
@page_title=""
@user=User.find(:first,:conditions=>["id=?",params[:id]])
if @user.first_login==1 and @[email protected]
@page_body="form"
@form="edit"
end
end
def get_profile
init
@page_body="view"
@page_title=""
@user=User.find(:first,:conditions=>["id=?",params[:id]])
if @user.first_login==1
@page_body="form"
@form="edit"
end
render :partial=>"view"
end
def get_form_user
init
@no_submenu=1
@page_body="form"
@page_title="New User"
@page="new_user"
@form="new"
@user=User.new
render :partial=> "/user/form"
118
end
def get_form_login
@no_submenu=1
@page_body="login"
@page_title="Login"
render :partial=> "/user/login"
end
def get_form_password
@page_body="form"
@page_title="Edit User"
@page="edit_user"
@form="edit"
@user=User.find(:first,:conditions=>["id=?",params[:id]])
render :partial=> "/user/form"
end
def get_miro_info
render :partial=>"/user/miro_info"
end
def delete
init
if @user_logged and @user_logged.type.to_s=="Administrator"
if request.post? and params[:users]
for i in params[:users].values
User.delete(i)
end
end
end
redirect_to(:controller=>:index,:action=>'index')
end
end
119
Appendice B: MODELS
class Administrator < User
end
class AnamnesisFamilyPathology < ActiveRecord::Base
belongs_to :patient
belongs_to :pathology
attr_accessible
:patient_id,:pathology_id,:mother,:father,:grandfather_paternal,:grandfat
her_maternal,:grandmother_paternal,:grandmother_maternal,:uncles_paternal
,:uncles_maternal,:aunts_paternal,:aunts_maternal,:brothers,:sisters,:con
sort,:childs,:daughters
validates_presence_of :patient_id,:pathology_id
end
class AnamnesisFamiliar < ActiveRecord::Base
belongs_to :patient
attr_accessible
:patient_id,:father_alive,:father_blood_group,:mother_alive,:mother_blood
_group,:allergy_id,:notes
validates_presence_of :patient_id
end
class AnamnesisAllergology < ActiveRecord::Base
belongs_to :patient
belongs_to :allergy
attr_accessible
:patient_id,:notes,:beginning_date,:ending_date,:allergy_id
validates_presence_of :patient_id,:allergy_id
end
class Allergy < ActiveRecord::Base
has_many :anamnesis_allergologies
end
class Patient < ActiveRecord::Base
has_many :anamnesis_pathologicals
has_many :anamnesis_allergologies
has_one :anamnesis_familiar
has_many :anamnesis_family_pathologies
has_one :anamnesis_physiological
has_many :visits
has_many :events
belongs_to :structure
120
belongs_to :born_location ,:class_name => 'Location',:foreign_key =>
'born_location_id'
belongs_to :residence_location,:class_name => 'Location',:foreign_key
=> 'residence_location_id'
attr_accessible
:name,:surname,:born_date,:sex,:born_location_id,:residence_address,:resi
dence_number,:residence_location_id,:residence_cap,:marital_status,:profe
ssion,:instruction,:dead,:dead_date,:telephone_number,:mail,:structure_id
validates_presence_of :name,:surname,:born_date,:born_location
end
class Visit < ActiveRecord::Base
belongs_to :patient
has_many :exam_files
belongs_to :exam
has_one :laboratory_exam
has_one :ecg
belongs_to :event
attr_accessible
:patient_id,:visit_date,:exam_id,:symptoms,:target_exam,:height,:weight,:
least_arterial_pressure,:maximal_arterial_pressure,:cardiac_frequency,
:conclusions, :target_exam
validates_presence_of :patient_id,:visit_date,:exam_id
end
require "digest/sha1"
class User < ActiveRecord::Base
belongs_to :lab
has_many :events
has_many :forum ,:dependent =>:destroy
has_many :reports ,:dependent =>:destroy
has_and_belongs_to_many
:exams,:foreign_key
:association_foreign_key => 'exam_id'
has_one :user_id
belongs_to :location
=>
'user_id',
validates_uniqueness_of :username
validates_presence_of
:name, :surname,:password,:username,:mail,:type
validates_format_of :mail, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[az]{2,})$/i,:if=>:mail?
validates_length_of :username, :minimum=>4, :too_short=>"please enter
at least %d character",:if=>:username?
validates_length_of :password, :minimum=>6, :too_short=>"please enter
at least %d character",:if=>:password?
attr_accessible
:username,:password,:mail,:name,:surname,:specialization,:address,:cap,:t
elephone_number,:fax,:type,:location_id,:created_at,:creator_id,:first_lo
gin
attr_accessor :password
attr_accessor :enable_cookie
def before_create
self.hashed_password = User.hash_password(self.password)
end
121
def after_create
@password = nil
end
def before_update
self.hashed_password
=
User.hash_password(self.password)
self.password and self.password!=""
end
def after_update
@password = nil
end
if
def validate_login
User.login(self.username, self.password)
end
def self.login(username,password)
hashed_password = hash_password(password || "")
find(:first,:conditions => ["username = ? and hashed_password =
?",username, hashed_password])
end
def self.validate_login_with_cookie(id, hashed_password)
find(:first,:conditions => ["id = ? and hashed_password = ?",id,
hashed_password])
end
def self.range_from_now time
today=Date.today
date=Date.parse(time.strftime('%Y/%m/%d'))
if today-date==0
"Today, "+time.strftime('%H:%M')
elsif today-date==1
time.strftime('Yesterday, %H:%M')
elsif today.month==date.month and today.year==date.year
time.strftime("%a, %d %H:%M")
else
time.strftime("%a, %d %b %y %H:%M")
end
end
private
def self.hash_password(password)
Digest::SHA1.hexdigest(password)
end
end
class Structure < ActiveRecord::Base
has_many :requesters
has_many :users
122
validates_presence_of
:name,:location_id
attr_accessible :name,:location_id,:address,:telephone_number
end
class Requester < User
belongs_to :structure
attr_accessible :structure_id
end
class Report < ActiveRecord::Base
belongs_to :event
belongs_to :user
attr_accessible :created_at,:event_id,:user_id,:body
validates_presence_of :event_id,:user_id,:body
end
class Pathology < ActiveRecord::Base
has_many :anamnesis_family_pathology
has_many :anamnesis_pathological
end
class Location < ActiveRecord::Base
has_many :users
has_many :patients
has_many :anamnesis_pathologicals
end
class LaboratoryExam < ActiveRecord::Base
belongs_to :visit
attr_accessible
:visit_id,:wbc,:rbc,:hb,:ht,:mcv,:plt,:creatinina,:azotemia,:ast,:alt,:so
dium,:potassium,:calcium,:pt,:pt_inr,:fibrinogeno,:ves,:pcr,:d_dimero,:ck
,:ck_mb,:ph,:pco2,:po2,:so2,:hco3,:sbe,:be
end
class Forum < ActiveRecord::Base
belongs_to :event
belongs_to :user
attr_accessible :user_id,:created_at,:event_id,:message
validates_presence_of :user_id,:event_id,:message
end
class Exam < ActiveRecord::Base
has_many :events
123
has_many :visits
has_and_belongs_to_many
:users,:foreign_key
:association_foreign_key => 'user_id'
validates_presence_of :name
end
class ExamFile < ActiveRecord::Base
belongs_to :visit
has_attachment
:storage
=>
'exam_files',:max_size => 100.megabytes
validates_as_attachment
=>
'exam_id',
:file_system,:path_prefix
=>
def full_filename(thumbnail = nil)
file_system_path = self.attachment_options[:path_prefix]
File.join(RAILS_ROOT,
file_system_path,
thumbnail_name_for(nil,
self.id))
end
def get_filename(thumbnail = nil)
file_system_path = "/home/mironrails/tesi/exam_files"
@thumb = self.thumbnail unless (@thumb = thumbnail) #checks if
thumbnails info already exist
File.join(file_system_path,thumbnail_name_for(@thumb, self.id.to_s))
end
def thumbnail_name_for(thumbnail = nil, asset = nil)
extension = filename.scan(/\.\w+$/) # extracts extension
return "#{asset}#{extension}" # change the filename to fit your
needs
end
end
class Event < ActiveRecord::Base
belongs_to :user
belongs_to :exam
belongs_to :patient
has_many :visits
has_many :reports
has_many :forums
attr_accessible :patient_id,:created_at,:closed_at,:user_id,:state
validates_presence_of :user_id,:state,:patient_id
end
class Ecg < ActiveRecord::Base
belongs_to :visit
attr_accessible
:visit_id,:rhythm,:frequency,:morphology_p,:interval_pr,:morphology_qrs,:
duration_qrs,:morphology_st,:axis_qrs,:morphology_t,:interval_qtc,:conclu
sions
124
end
class Doctor < User
validates_presence_of :username,:password,:mail
end
class AnamnesisPhysiological < ActiveRecord::Base
belongs_to :patient
attr_accessible
:patient_id,:alvo_notes,:fecal_incontinence_notes,:dyuresis_notes,:urinar
y_inconsistency_notes,:digestion_notes,:sleep_notes,:blood_group,:blood_g
roup_partner,:blood_group_notes
validates_presence_of :patient_id
end
class AnamnesisPathological < ActiveRecord::Base
belongs_to :patient
belongs_to :location
belongs_to :pathology
attr_accessible
:patient_id,:pathology_id,:onset_age_yy,:state_id,:flag_hospitalization,:
entry_date,
:resignations_date,:diagnosis,:hospital,:location_id,:resignations_letter
validates_presence_of :patient_id,:pathology_id
end
125
BIBLIOGRAFIA
™ Mokabyte : http://www.mokabyte.it , rivista dedicata a Java
™ Wikipedia : http://www.wikipedia.org , enciclopedia libera scritta dagli utenti del web
™ Ruby : http://www.ruby-lang.org , sito ufficiale di Ruby
™ Ruby on Rails : http://www.rubyonrails.org/ , sito ufficiale di Ruby on Rails
™ Prototype : http://www.prototypejs.org/ , sito ufficiale del framework Prototype
™ Ubuntu : http://help.ubuntu.com , guida per l’installazione di Ubuntu server e di Ruby
on Rails
™ Apache : http://www.apache.org/ , Application Server Apache
™ MySql : http://www-it.mysql.com/ , sito ufficiale del DBMS MySql
™ SSH : http://www.oscene.net/site/sysadmin/networking/howto-configurare-neldettaglio-ssh
™ Mantis : http://www.mantisbt.org/ , sito ufficiale del Bug Tracker Mantis
™ Christophe Portenuve : “Prototype and script.aculo.us” , consultazione informazioni sul
framework Prototype
™ Dave Thomas : “Programming Ruby” , consultazione informazioni su Ruby
™ Jules J. Berman : “Ruby Programming for Medicine and Biology “, consultazione
informazioni avanzate su Ruby e la telemedicina
™ Dave Thomas, David Heinemeier Hansson : “Sviluppare applicazioni Web con Rails”,
informazioni avanzate su Ruby on Rails
™ Bruce Tate : “From Java to Ruby”, consultazione differenze tra Java e Ruby
™ Scott Raimond : “Ajax on Rails” , informazioni sull’utilizzo di Ajax con Rails
™ Danny Goodman : “Javascript Bible” , consultazione informazioni su Javascript
™ Andre Lewis, Michael Purvis,Jeffrey Sambells, e Cameron Turner : “Google Maps
Applications with Rails and Ajax”, informazione sull’utilizzo dell’API Google Maps in
Rails
™ Brian Pfaffenberger, Steven M. Schafer,Charles White, Bill Karow : “HTML,XHTML
e CSS Bible”
126