Make your e-book… fatti l'e-book!

per una diffusione globale dei propri testi

costruire un efficiente sistema di recensioni

Lascia un commento

 CROP CIRCLE

(CC) Marco Fedele / Flickr

Ho da sempre avuto davanti ai miei occhi il sistema di recensioni di Amazon, quello di Goodreads, di recente quello di Apple, poi un bel giorno Kobo annuncia il suo sistema di recensioni. Tutto nuovo.

Bello. È utile? Se fosse stato fatto con criterio sì.

In data 18 gennaio 2015 all’indirizzo: http://store.kobobooks.com/it-IT/ebook/gioco-pericoloso-maresciallo-maggio ci sono 4 identiche valutazioni da parte di uno stesso utente a un ebook. Varia solo il numero di stelle; sono a tutti gli effetti 4 recensioni indipendenti dello stesso utente allo stesso ebook. Questo vuol dire che chi ha fatto questa cosa non può modificare la recensione o che ogni modifica viene vista come una nuova recensione?

Mi sono chiesto allora quanto sia difficile per un sistemista Linux come me (e parzialmente sviluppatore software) fare un sistema di recensioni in cui un utente può recensire un libro soltanto una volta e avere la possibilità di modificare la propria recensione. Risposta: non molto, per una prima bozza bastano 5 minuti. E si fa anche meglio di quegli store dove si duplicano le recensioni, ovvero dove un utente può mettere diverse recensioni con diversi rates (le famose stelline) sempre allo stesso libro.

Eppure io non posseggo uno store ebook internazionale, non possiedo un’azienda di informatica. Io non ho nemmeno più un lavoro pagato perché non ci sono soldi e non si sa quando mi pagheranno per un lavoro già svolto. Possibile che io in queste condizioni sono in grado di fare meglio di chi si suppone avere capitali e mezzi tecnici come un ebook store internazionale? Pare banale, ma la risposta è: SÌ, POSSO.

Cerco un lavoro dignitoso e pagato. Qualcuno ne offre?

MySQL e tre tabelle ed è fatto

Una base di dati è un archivio di informazioni. Pensiamo alla schede di uno schedario. A un elenco telefonico dove ci sono nome, indirizzo e numero di telefono.

Per i libri è la stessa cosa. C’è un libro e quindi un autore, un codice ISBN, un titolo, ecc… C’è un utente dello store: email e suo nome. E poi ci sono le recensioni che mettono i relazione queste due schede. L’utente con indirizzo email X recensisce il libro Y.

Come si crea il tutto? La base di dati usa quello che si chiama linguaggio SQL. Definisce le schede di cui sopra e permette con delle istruzioni di creare le schede con le informazioni. Basta creare una semplice base dati con tre tabelle (pensate alla tabella come un insieme di schede che contengono lo stesso tipo di informazioni). Una con tutti i dati su un libro, una con tutti i dati degli utenti e un’altra che rappresenta la relazione utente/recensione di un dato libro:

create database user_review;
use user_review;
create table book
(
isbn varchar(13) PRIMARY KEY,
title varchar(40) not null,
author varchar(40) not null,
description varchar(5000) not null,
DRM bool,
published bool
);
create table user(
email varchar(40) PRIMARY KEY,
nickname varchar(40) not null
);
create table review(
isbn varchar(13) not null,
user_email varchar(40) not null,
user_review varchar(5000) not null,
stars int,
published bool,
PRIMARY KEY (isbn,user_email),
FOREIGN KEY (isbn) REFERENCES book(isbn),
FOREIGN KEY (user_email) REFERENCES user(email)
);

La PRIMARY KEY (detta chiave primaria) mi dice che ci può essere una sola riga della tabella che assume quel valore. Nel caso del libro è il codice ISBN che è un codice internazionale a cui si legano tutti i dati del libro.

La FOREIGN KEY definisce il vincolo esterno. Ovvero mi dice che per fare una recensione a un libro X da parte di un utente Y. Il libro X già deve esistere e la stessa cosa vale per l’utente Y.

Un libro (tabella book) con un dato codice ISBN è unico. Non ci possono essere più libri con lo stesso ISBN. Un utente (tabella user) ha un suo nickname (può essere il suo nome e cognome o un alias o quel che vuole) e l’indirizzo email può portare a una sola registrazione. Non posso avere lo stesso indirizzo email associato a nomi diversi. Posso cambiare il nome se voglio, ma la chiave primaria della tabella user resta email.

Infine, la tabella delle recensioni (review nel codice SQL di cui sopra). Posso avere un utente che recensisce un libro solo una volta. La chiave primaria è costituita dalla coppia ISBN/email utente. Questo perché posso avere vari libri (ciascuno identificato dal suo codice ISBN) recensiti dallo stesso utente, un codice ISBN di un libro che è stato recensito da diversi utenti, ma non lo stesso libro (con suo codice ISBN univoco) recensito più volte dallo stesso utente. Questa riga della tabella resta unica nella coppia ISBN/email. E, ovviamente, l’ISBN deve esistere nella tabella dei libri (book) e l’email deve esistere nella tabella degli utenti (user).

Creiamo la base di dati in MySQL (un programma che fa da RDBMS, ovvero Sistema di gestione delle basi di dati relazionali), con il codice SQL di cui sopra, e verifichiamo che ci sia una sola recensione utente per lo stesso codice ISBN. La verifica è semplice. Basta violare la regola e vedere come risponde la base di dati, ovvero impedendo l’inserimento della recensione.

Di seguito è riportato il codice SQL che inserisce un paio di libri nella base dati, un paio di utenti e relative recensioni. Nel codice ci sono gli errori di inserimento (c’è l’apposito commento chiuso tra tra /* e */) cui si parlava. Errori per l’appunto verificati di modo da avere sempre il concetto: un utente, un libro, ergo, una sola recensione.

insert into book values("1234567890123","Un titolo da sballo","Pinco Pallino", "La storia di un libro che impara a camminare da solo", false, true);
insert into book values("1134567890123","Un titolo da choc","Fra Giorgio", "La storia di un frate che cerca lavoro in un night club", false, true);
insert into user values("zio.mario@dominio.it", "Zio Mario");
insert into user values("alberto@dominio.it", "Alberto De Marco");
insert into review values("1234567890123", "zio.mario@dominio.it", "Un libro angosciante sul concetto di vita propria del libro. Una storia superbamente narrata.", 5, false);
/* errore sulla insert: un utente non deve poter inserire due recensioni diverse per il medesimo libro: stesso ISBN */
insert into review values("1234567890123", "zio.mario@dominio.it", "Un libro allucinante scritto coi piedi.", 1, false);
/* errore sulla insert: un utente non registrato non puo' inserire una recensione */
insert into review values("1234567890123", "franco.liborio@dominionuovo.it", "Un libro che non ha senso. Scritto coi piedi, ma divertente.", 2, false);
/* ricava le stelle e la recensione precedentemente data a libro con ISBN 1234567890123 per l'utente registrato con l'email zio.mario@dominio.it */
select stars,user_review from review where isbn="1234567890123" and user_email="zio.mario@dominio.it";
/* aggiorna la recensione dell'utente registrato zio.mario@dominio.it del libro con ISBN 1234567890123 */
update review set user_review="Un libro angosciante sul concetto di vita propria del libro. Una storia superbamente narrata, priva direfusi e ricca di dettagli che spingono sempre di più nella lettura.", stars=4 where isbn="1234567890123" and user_email="zio.mario@dominio.it";
/* ricava le stelle e la recensione precedentemente data a libro con ISBN 1234567890123 per l'utente registrato con l'email zio.mario@dominio.it */
select stars,user_review from review where isbn="1234567890123" and user_email="zio.mario@dominio.it";
/* rende disponibile la recensione del libro con isbn 1234567890123 a tutti i visitatori del sito */
update review set published=true where isbn="1234567890123";
/* verifica la disponibilità sul sito della recensione del libro con isbn 1234567890123 */
select published from review where isbn="1234567890123";

Provando a eseguire il tutto in una console MySQL vediamo che la base di dati va in errore quando si violano i vincoli di duplicazione recensioni e di recensione da parte di un utente non registrato. Ecco l’output prodotto:

mysql> create database user_review;
Query OK, 1 row affected (0.00 sec)
mysql>
mysql> use user_review;
Database changed
mysql>
mysql> create table book
-> (
-> isbn varchar(13) PRIMARY KEY,
-> title varchar(40) not null,
-> author varchar(40) not null,
-> description varchar(5000) not null,
-> DRM bool,
-> published bool
-> );
Query OK, 0 rows affected (0.22 sec)
mysql>
mysql> create table user(
-> email varchar(40) PRIMARY KEY,
-> nickname varchar(40) not null
-> );
Query OK, 0 rows affected (0.22 sec)
mysql>
mysql> create table review(
-> isbn varchar(13) not null,
-> user_email varchar(40) not null,
-> user_review varchar(5000) not null,
-> stars int,
-> published bool,
-> PRIMARY KEY (isbn,user_email),
-> FOREIGN KEY (isbn) REFERENCES book(isbn),
-> FOREIGN KEY (user_email) REFERENCES user(email)
-> );
Query OK, 0 rows affected (0.26 sec)
mysql>
mysql> insert into book values("1234567890123","Un titolo da sballo","Pinco Pallino", "La storia di un libro che impara a camminare da solo", false, true);
Query OK, 1 row affected (0.02 sec)
mysql> insert into book values("1134567890123","Un titolo da choc","Fra Giorgio", "La storia di un frate che cerca lavoro in un night club", false, true);
Query OK, 1 row affected (0.03 sec)
mysql>
mysql> insert into user values("zio.mario@dominio.it", "Zio Mario");
Query OK, 1 row affected (0.01 sec)
mysql> insert into user values("alberto@dominio.it", "Alberto De Marco");
Query OK, 1 row affected (0.02 sec)
mysql>
mysql> insert into review values("1234567890123", "zio.mario@dominio.it", "Un libro angosciante sul concetto di vita propria del libro. Una storia superbamente narrata.", 5, false);
Query OK, 1 row affected (0.01 sec)
mysql>
mysql> /* errore sulla insert: un utente non deve poter inserire due recensioni diverse per il medesimo libro: stesso ISBN */
mysql> insert into review values("1234567890123", "zio.mario@dominio.it", "Un libro allucinante scritto coi piedi.", 1, false);
ERROR 1062 (23000): Duplicate entry '1234567890123-zio.mario@dominio.it' for key 'PRIMARY'
mysql>
mysql> /* errore sulla insert: un utente non registrato non puo' inserire una recensione */
mysql> insert into review values("1234567890123", "franco.liborio@dominionuovo.it", "Un libro che non ha senso. Scritto coi piedi, ma divertente.", 2, false);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`user_review`.`review`, CONSTRAINT `review_ibfk_2` FOREIGN KEY (`user_email`) REFERENCES `user` (`email`))
mysql>
mysql> /* ricava le stelle e la recensione precedentemente data a libro con ISBN 1234567890123 per l'utente registrato con l'email zio.mario@dominio.it */
mysql> select stars,user_review from review where isbn="1234567890123" and user_email="zio.mario@dominio.it";
+-------+-----------------------------------------------------------------------------------------------+
| stars | user_review |
+-------+-----------------------------------------------------------------------------------------------+
| 5 | Un libro angosciante sul concetto di vita propria del libro. Una storia superbamente narrata. |
+-------+-----------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql>
mysql> /* aggiorna la recensione dell'utente registrato zio.mario@dominio.it del libro con ISBN 1234567890123 */
mysql> update review set user_review="Un libro angosciante sul concetto di vita propria del libro. Una storia superbamente narrata, priva direfusi e ricca di dettagli che spingono sempre di più nella lettura.", stars=4 where isbn="1234567890123" and user_email="zio.mario@dominio.it";
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql>
mysql> /* ricava le stelle e la recensione precedentemente data a libro con ISBN 1234567890123 per l'utente registrato con l'email zio.mario@dominio.it */
mysql> select stars,user_review from review where isbn="1234567890123" and user_email="zio.mario@dominio.it";
+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| stars | user_review |
+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 4 | Un libro angosciante sul concetto di vita propria del libro. Una storia superbamente narrata, priva direfusi e ricca di dettagli che spingono sempre di più nella lettura. |
+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql>
mysql> /* rende disponibile la recensione del libro con isbn 1234567890123 a tutti i visitatori del sito */
mysql> update review set published=true where isbn="1234567890123";
Query OK, 1 row affected (0.02 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql>
mysql> /* verifica la disponibilità sul sito della recensione del libro con isbn 1234567890123 */
mysql> select published from review where isbn="1234567890123";
+-----------+
| published |
+-----------+
| 1 |
+-----------+
1 row in set (0.00 sec)

Ecco. È ovvio che la base di dati SQL deve essere in cluster (ridondata, diversi computer devono custodire i dati e sincronizzare le modifiche), deve essere distribuita (magari collocata in diversi punti del paese o della stessa città o nello stesso edificio, ma su pian diversi, per sfruttare diversi punti di accesso in base al fatto che l’utenza di uno store internazionale è grossa e non si riesce a soddisfare tutte le richieste con un solo computer). Le chiavi primarie magari non sono stringhe di testo, ma un identificativo numerico, magari un autoincremento o altro, bisogna creare degli indici, ecc, ecc (sarà la figura professionale del DB Administrator a consigliare come creare e ottimizzare le tabelle di cui sopra) e il codice che esegue queste operazioni sull’archivio dati deve essere fatto da un sito: l’utente apre la pagina internet del sito e inserisce la sua recensione.

Come si fa questa cosa? Basta scrivere un po’ di codice PHP o JSP che interagisce con la base di dati (magari non usare nemmeno MySQL, ma valutare il miglior database a seconda di quanto si può spendere e dell’efficienza da ottenere) e il gioco è fatto. Infatti non deve essere nemmeno la base dati che deve dare un errore sull’operazione di inserimento per capire che qualcosa non va, deve essere l’applicazione che, prima di chiedere di scrivere e inserire una recensione, deve cercarla. Se l’utente già ha recensito il libro allora potrà fare le dovute modifiche, altrimenti gli si presenta il form dove inserire la sua recensione che la base dati accoglierà senza errori sui vincoli.

Inconcepibile e semplicistico

Come facciano alcuni detentori di store internazionali a cadere in questi errori grossolani e di progettazione non si spiega. Amazon e Apple sono alieni che lo fanno e pure bene? Come anche non si spiega quando aziende italiane di software sembrano vendere patate e cipolle anziché software per poi meravigliarsi di tante cose, incluso quando l’Italia tutta viene considerata fuori dalla concorrenza rispetto ad aziende e startup europee (e d’oltre oceano). Il fatto è che si pretende moltissimo e si vuol pagare nulla o quasi e questo porta a tante conseguenze, forse le aziende informatiche che non sanno nulla di processi tecnici e non hanno competenze tecniche di livello e che non vogliono formare il personale dovrebbero seriamente contemplare l’idea di trasformarsi in aziende che vendono patate, cipolle, carciofi, carote e verdure in genere. D’altra parte nessuno smette di mangiare patate, cipolle, carciofi, carote e verdure, no? E se guadagnerebbe in salute. Dipendenti e clienti di pseudo aziende informatiche.

Autore: giovanni

Scrivo su http://giovanniventuri.com/ e faccio e-book per professione su https://makeyourebook.me/

Lascia un commento

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...