Sei sulla pagina 1di 38

Esame: 3 ore di scritto (quiz + esercizi + computer esercizi (ci puó dare il test e scrivere il

codice o viceversa)) per gli esercizi si puó usare il materiale ma non per il quiz.
L'esame è diviso in 3 ore ed il tempo che salvi puoi usarlo nella parte successiva.

Tesi: media 6-7 punti

Lezione 1
Why design matters for security?
Meglio puntare alla stabilità che all'efficienza.
Quando faccio un get dobbiamo sapere se quel parametro su cui facciamo get é mutable
oppure no e questo dipende dal fatto che per array o matrici viene passato il riferimento e
quindi possono mutare. Stessa cosa per le stringhe in c++.

Nella realizzazione di un progetto dobbiamo parlare con i clienti per le principali funzionalità,
implementare la logica di business del software e poi la sicurezza che è un livello
trasparente. Quando il software è pronto per la release dobbiamo fare dei test di
penetrazione e di sicurezza per controllare il funzionamento.

Lezione 2
CIA-T:
● Confidentiality: mantenere segreto ciò che non dev'essere pubblico;
● Integrity: le informazioni possono cambiare solo nel modo autorizzato;
● Availability: assicurare l'accesso alle informazioni quando necessario;
● Traceability: tenere traccia di chi accede o modifica i dati.

final in java significa che puoi assegnare quella variabile che poi non cambierà diventando
immutabile.

static in java significa che importiamo in maniera statica i metodi

notNull fa un check se quella stringa è vuota, se è vuota restituisce un nullPointException

validateForXSS fa un check della validità. Se la single quote ' non è possibile non c'è SQL
injection.
Trim è un sanificatore che elimina ció che impostiamo.
Qui è inutile mettere private sulla string value perchè abbiamo messo final, il che prevede
un'unica modifica e poi le stringhe in java sono immutable, quindi non potremmo modificarla
nuovamente. Abbiamo messo una specie di get con il return di value, quindi non cambia se
sia public.

Deep Modeling
Mai usare float o double per valori precisi perché per definizione float e double sono valori
non precisi.

Se un valore intero dev'essere positivo dovremmo usare unsigned.

Anche per le stringhe non dobbiamo concedere qualsiasi tipo di stringa per sicurezza. Se
abbiamo due stringhe e le scambiamo il compilatore non può darci nessun aiuto su questo.

Occorre rappresentare tutti i concetti del dominio come una classe. Ogni classe è
responsabile della validazione dei suoi dati. Se non usiamo una classe dobbiamo ripetere la
validazione piú volte nel codice.

Casa
La tipizzazione statica è un tipo particolare di controllo statico , che significa verificare la
presenza di bug in fase di compilazione.

Ci sono tre tipi di controllo automatico che un linguaggio può fornire:


● Controllo statico: il bug viene rilevato automaticamente prima ancora che il
programma venga eseguito;
● Controllo dinamico: il bug viene rilevato automaticamente quando viene eseguito il
codice;
● Nessun controllo: il linguaggio non ti aiuta affatto a trovare l'errore. Devi stare
attento tu stesso, altrimenti finirai con risposte sbagliate.
Inutile dire che catturare un bug staticamente è meglio che catturarlo dinamicamente, e
catturarlo dinamicamente è meglio che non catturarlo affatto.
In java le istruzioni devono trovarsi all'interno di un metodo che a sua volta deve trovarsi
all'interno di una classe. Un metodo può essere static e lo chiamiamo tramite la classe.

I bravi programmatori evitano le cose che cambiano, perché potrebbero cambiare


inaspettatamente.

Revisione del codice


La revisione del codice ha in realtà due scopi:
● Miglioramento del codice: trovare bug, anticipare possibili bug, verificare la
chiarezza del codice e verificarne la coerenza con gli standard di stile del progetto.
● Migliorare il programmatore: la revisione del codice è un modo importante in cui i
programmatori imparano e si insegnano a vicenda sulle nuove funzionalità del
linguaggio, sui cambiamenti nella progettazione del progetto o sui suoi standard di
codifica e sulle nuove tecni

Il codice duplicato è un rischio per la sicurezza. Se hai codice identico o molto simile in due
posti, il rischio fondamentale è che ci sia un bug in entrambe le copie e che qualche
manutentore risolva il bug in un posto ma non nell'altro.

I bravi sviluppatori di software scrivono commenti nel loro codice e lo fanno con giudizio. I
buoni commenti dovrebbero rendere il codice più facile da comprendere, più sicuro dai bug
(perché sono stati documentati presupposti importanti) e pronto per il cambiamento.

Evita le variabili globali. Una variabile globale è:

● una variabile , un nome il cui valore può essere modificato.


● che sia globale , accessibile e modificabile da qualsiasi punto del programma.

In Java viene dichiarata una variabile globale public static. Il public modificatore lo
rende accessibile ovunque e static significa che esiste una singola istanza della
variabile.

Tuttavia, con un modificatore aggiuntivo, public static final il tipo della variabile è
immutabile, il nome diventa costante globale. Una costante globale può essere letta
ovunque nel programma ma mai riassegnata o modificata, quindi i rischi scompaiono.

Quando disegniamo diagrammi istantanei, è importante distinguere tra diversi tipi di variabili:

● variabili locali all'interno di un metodo;


● variabili di istanza all'interno di un'istanza di un oggetto;
● variabili statiche associato ad una classe.

I metodi dovrebbero restituire risultati, non stamparli.

Lezione 3
Domain-Driven Design
E’ una metodologia per lo sviluppo di software complessi. Si concentra sul dominio. Se
dobbiamo incrementare qualcosa dobbiamo capire cosa dobbiamo incrementare parlando
con il cliente.

Il modello del sistema non può essere ambiguo e dev’essere rigorosamente definito e il
sistema deve fare soltanto quel lavoro per cui è stato progettato. Per ogni contesto del
sistema dobbiamo creare un modulo, i quali possono comunicare tra loro e scambiare dati.
Questa suddivisione in moduli facilità lo sviluppo del software. Un modello è un’astrazione
della realtà che in questo caso facilità la progettazione ed il funzionamento del software. Ci
sono diverse rappresentazioni dello stesso modello. Il modello che scegliamo dipende dal
contesto. Il principio da utilizzare è KISS (keep it simple and stupid).
Vogliamo semplificare il modello per essere precisi e formali, eliminando forme di ambiguità.
Semplificare troppo non è un bene, e se i tipi diventano troppo generici significa che
potrebbe esserci un problema di sicurezza. Per risolvere il problema di oversimplify significa
che non abbiamo capito il dominio. Dobbiamo continuare a chiedere all’esperto del dominio
finché non è definito formalmente il modello.
Quando parliamo con un cliente ci dev’essere un accordo.

Entità
Un'entità rappresenta qualcosa che può cambiare nel nostro programma. Siccome un’entità
può cambiare abbiamo bisogno di qualcosa per distinguerla che prende il nome di identità.
L’identità dell’entità è un identificatore che può essere un numero progressivo oppure una
stringa o altro che fa distinguerlo tra le varie entità. L’identità dell’entità è associata all’intera
vita dell’entità. L’entità può contenere altri oggetti, entità oppure value. Essa è responsabile
della coordinazione delle operazioni sugli oggetti di cui è proprietario.

Lezione 4
Value Object
Il value object è immutabile e non ha un identificatore perché è definito dal suo valore che
non può cambiare (per esempio una banconota da 5€ è uguale a tutte le altre banconote da
5€). Può essere utilizzato come un attributo di un'entità e può fare riferimento ad un’entità.

E’ importante impostare dei constraints perché se dobbiamo fare una statistica possiamo
creare un’array statico che possiamo scorrere in tempo lineare, mentre se trattiamo le cose
con oggetti primitivi andiamo ad occupare tutta la memoria.

Aggregate
Gli aggregati sono delle porzioni di modello che non sono scelti a caso ma secondo ragioni
tecniche. Esse rappresentano un’unità. Un aggregate deve avere una radice, ovvero
un’entità all’interno dell’aggregato ed un confine. Solo la radice dell’aggregato può essere
referenziato dall’esterno. La radice può fare riferimento a tutte le entità nel confine
dell’aggregato.

I termini possono avere significati diversi in contesti diversi. Pertanto, è essenziale definire i
"bounded contexts" per stabilire confini chiari tra le diverse parti del sistema e gestire la
comunicazione tra di loro.
Il migliore approccio è capire la comunicazione fra i differenti dipartimenti.

Domande
Casa
Diagrammi snapshot
I diagrammi snapshot rappresentano lo stato interno di un programma in fase di esecuzione.
Ecco perché usiamo diagrammi istantanei:
● Per illustrare concetti come tipi primitivi vs. tipi di oggetto, valori immutabili vs.
riferimenti non riassegnabili, aliasing del puntatore, stack vs. heap, astrazioni vs.
rappresentazioni concrete;
● Per spiegare la progettazione per il progetto team.

Valori primitivi
I valori primitivi sono rappresentati da costanti nude. La freccia in arrivo è un riferimento al
valore di una variabile o di un campo oggetto.

Valori degli oggetti


Un valore oggetto è un cerchio etichettato in base al tipo. Quando vogliamo mostrare più
dettagli, scriviamo i nomi dei campi al suo interno, con frecce che indicano i loro valori. Per
ulteriori dettagli, i campi possono includere i tipi dichiarati.

Valori immutabili
Gli oggetti immutabili sono indicati in un diagramma istantaneo da un doppio bordo, al contrario
quelli mutabili.

Riferimenti non riassegnabili


Java ci dà anche l'immutabilità per i riferimenti: variabili che vengono assegnate una volta e
mai riassegnate. Per rendere un riferimento non riassegnabile, dichiararlo con la parola
chiave finale:
final int n = 5;
In un diagramma snapshot, un riferimento non riassegnabile () è indicato da una doppia
freccia.

Casa
Oggetti immutabili in Java
Un oggetto immutabile è un oggetto il cui stato interno rimane costante dopo che è stato
interamente creato. In Java, le variabili sono modificabili per impostazione predefinita, il che
significa che possiamo cambiare il valore che contengono. Utilizzando la parola chiave
finale quando si dichiara una variabile, il compilatore Java non ci consente di modificare il
valore di tale variabile. Si noti che final ci vieta solo di modificare il riferimento contenuto
nella variabile, non ci protegge dal modificare lo stato interno dell'oggetto a cui fa
riferimento.
Poiché lo stato interno di un oggetto immutabile rimane costante nel tempo, possiamo
condividerlo in modo sicuro tra più thread. Gli oggetti immutabili non cambiano il loro stato
interno nel tempo, sono thread-safe e privi di effetti collaterali. A causa di queste proprietà,
gli oggetti immutabili sono particolarmente utili anche quando si ha a che fare con ambienti
multi-thread

Mutabilità e immutabilità
I tipi immutabili sono più sicuri dai bug, più facili da capire e più pronti al cambiamento. La
mutabilità rende più difficile capire cosa sta facendo il tuo programma e molto più difficile far
rispettare i contratti. Questo è un problema fondamentale con le strutture dati mutabili.
Riferimenti multipli allo stesso oggetto mutabile (chiamati anche alias per l'oggetto) possono
significare che più punti nel tuo programma, possibilmente ampiamente separati, fanno
affidamento su quell'oggetto per rimanere coerenti. Per dirla in termini di specifiche, i
contratti non possono più essere applicati in un solo posto, ad esempio tra il client di una
classe e l'implementazione di una classe. I contratti che coinvolgono oggetti mutabili ora
dipendono dal buon comportamento di tutti coloro che hanno un riferimento all'oggetto
mutabile.

Tipi immutabili utili


Poiché i tipi immutabili evitano così tante insidie, enumeriamo alcuni tipi immutabili di uso
comune nell'API Java:
● I tipi primitivi e i wrapper primitivi sono tutti immutabili . Se hai bisogno di calcolare
con numeri grandi BigInteger e BigDecimal sono immutabili.
● Non utilizzare Date messaggi di posta elettronica modificabili, utilizzare il tipo
immutabile appropriato in java.time base alla granularità del cronometraggio di cui
hai bisogno.
● Per creare raccolte immutabili da alcuni valori noti, utilizzare List.of, Set.of e Map.of.
● Le solite implementazioni di List, Set, e Map sono tutte mutabili: ArrayList, HashMap,
ecc. La Collections classe di utilità dispone di metodi per ottenere visualizzazioni
immodificabili di queste raccolte mutabili:
○ Collections.unmodifiableList
○ Collections.unmodifiableSet
○ Collections.unmodifiableMap
● Prima di passare una raccolta mutabile a un'altra parte del nostro programma,
possiamo avvolgerla in un wrapper non modificabile. Dovremmo stare attenti a quel
punto a dimenticare il nostro riferimento alla collezione mutabile, per evitare di
mutarla accidentalmente. (Un modo per farlo è lasciarlo uscire dall'ambito.) Proprio
come un oggetto mutabile dietro un final riferimento può essere mutato, la raccolta
mutabile all'interno di un wrapper immodificabile può ancora essere modificata da
qualcuno con un riferimento ad esso, sconfiggendo il wrapper .
● In alternativa, utilizzare List.copyOf, ecc., per creare copie superficiali immodificabili
di raccolte mutabili.
● Collections fornisce anche metodi per ottenere raccolte vuote immutabili:
Collections.emptyList, ecc.
Esempio
List<String> arraylist = new ArrayList<>();
arraylist.add("hello");
List<String> unmodlist = Collections.unmodifiableList(arraylist);
// unmodlist should now always be [ "hello" ]

arraylist.add("goodbye");
System.out.println(unmodlist);

stampe ["ciao" "arrivederci"]

I wrapper non ci impediscono di modificare la raccolta wrapper se abbiamo ancora un


riferimento ad essa!

Code constructs promoting security


Risolvere problemi di sicurezza nel codice:
● Immutability: L'immutabilità serve per risolvere problemi legati all’integrità e agli
availability.
● Fail fast: strategia per risolvere input irregolari. Prevede di bloccare l’elaborazione
dei dati se non rispettano delle specifiche precise;
● Validation: strategia che rende l'input conforme con le specifiche.

Immutability
Un oggetto è mutabile se permette cambiamenti, immutabile altrimenti. è preferibile che
rendiamo i nostri oggetti immutabili al fine di prevenire attacchi DOS.

Fail fast
I dati non validi vengono bloccati prima di creare oggetti invalidi. Ogni classe deve definire
una sorta di contratto tra prerequisiti che i dati devono soddisfare per ottenere la
postcondizione, ovvero la costruzione dell’istanza dell’oggetto.

Contracts
Un contratto è un formalità da rispettare al fine di evitare oggetti invalidi con l’obiettivo di
creare il codice più sicuro.
Dobbiamo definire i contracts quando:
● Abbiamo metodi pubblici;
● Per i metodi con visibilità di package se il package è grande ed il metodo è molto
utilizzato;
● Per i metodi privati non abbiamo bisogno dei contratti;
● Per i metodi protetti nemmeno.
Dobbiamo partire da un buon costruttore al fine di evitare di creare invalide istanze.

Validazione
La validazione è una fase dove rendiamo il nostro input valido. Tuttavia l’input validation
dipende dal contesto del modello in cui ci troviamo. Inoltre dobbiamo validare tutti i dati, da
quelli più semplici a quelli più complessi.

Tipi di validazione
Queste validazioni vanno fatte in questo ordine, dal più alto al più basso, perché se facciamo
un controllo semantico su un dato in input molto grande, esso richiede molta computazione,
il che si traduce che il nostro server ha un costo di elaborazione maggiore. Per questo
dobbiamo prima occuparci della size.
● Origine: i dati provengono dal legittimo mittente? Per un attaccante non è così
costoso inviare dati dannosi. Occorre prevenire attacchi DoS e DDos e lo facciamo
controllando gli indirizzi IP. Dobbiamo fare attenzione allo spoofing richiedendo una
chiave di accesso alle nostre API, token o chiavi univoche;
● Size: la size è ragionevole? Dobbiamo capire qual è la nostra ragionevole size ed
essa dipende dal contesto;
● Contesto lessicografico: l’input contiene solo caratteri ammissibili? verificare che i
dati ricevuti siano quelli consentiti
● Sintattico: Il formato dei dati è corretto? controllare se i caratteri sono nel posto
giusto, tramite delle regex;
● Semantico: i dati hanno un senso nel contesto in cui siamo? questo generalmente
richiede molto tempo. Determinare se i dati sono consistenti rispetto allo stato del
sistema.

Lezione 5
Generics Java
Una classe generica viene implementata esattamente come una classe non generica.
L'unica differenza è che contiene una sezione di parametri di tipo. Possono esistere più tipi
di parametro, separati da una virgola. Le classi, che accettano uno o più parametri, sono
note come classi con parametri o tipi con parametri.
Lezione 6
Domain primitives
I "Domain Primitives" sono i value object fondamentali nel progettare un sistema software,
rappresentando concetti chiave all'interno di un dominio specifico.
Nella creazione dei primitivi di dominio, di solito vengono applicate invarianti (regole o
vincoli) per garantire la loro validità e coerenza. Un oggetto dovrebbe esistere soltanto se
esso è valido.
I primitivi di dominio non dovrebbero utilizzare tipi generici o consentire valori nulli. Ciò
assicura che rappresentino accuratamente i valori specifici del dominio ed evita ambiguità.
Ogni concetto all'interno del dominio dovrebbe essere rappresentato in modo adeguato dai
primitivi di dominio in modo da avere un codice chiaro ed organizzato.
Il significato di un primitivo dominio è dipendente dal contesto e potrebbe essere necessario
definirli per allinearlo meglio con gli obiettivi specifici del progetto. Limitare o estendere la
definizione secondo necessità è accettabile.
È consigliabile evitare di rendere le definizioni più permissive, poiché ciò può generare
confusione. È preferibile invece introdurre nuovi termini e utilizzare l'ereditarietà quando
necessario.
Creare una libreria di primitivi di dominio fin dall'inizio, coprendo tutti i termini rilevanti nel
dominio per garantire coerenza e chiarezza.
Nel contesto della definizione di un'API REST, è consigliabile evitare di esporre il modello di
dominio interno. Ciò impedisce che i futuri cambiamenti diventino costosi, poiché tutti gli
utenti dell'API dovrebbero adattarsi a tali cambiamenti.
Gli oggetti da leggere una volta sono progettati per essere letti solo una volta e possono
aiutare a identificare utilizzi inattesi o non autorizzati. Spesso sono costituiti da primitivi di
dominio e impediscono la serializzazione di dati sensibili, l'ereditarietà e le estensioni

Utilizzare i primitivi di dominio per argomenti dei metodi, argomenti dei costruttori, tipi di
ritorno e attributi delle entità offre diversi vantaggi:
● L'input è sempre valido.
● La convalida è coerente.
● Il codice delle entità è più conciso e leggibile.
● Il sovraccarico è minimo rispetto ad altre operazioni del sistema.

In conclusione, i primitivi di dominio sono fondamentali per la costruzione di un sistema


software che rappresenti in modo accurato i concetti all'interno di un dominio specifico,
applichi coerenza e assicuri la validità dei dati. Forniscono un approccio strutturato ed
organizzato per modellare il dominio e aiutano nello sviluppo di codice più sicuro e più
facilmente mantenibile.
For Illegal State we use validate state, isTrue is only for illegal argouments
DRY: don’t repeat yourself
Lezione 7
Ensuring integrity of state
Non tutto è immutabile. Nel Drive-Design Domain gli stati mutabili sono le entità.
Come possiamo creare consistenti entità? Dobbiamo utilizzare il builder pattern.
Esistono diversi modi per gestire le entità.

È importante creare all’inizio consistenti entità altrimenti maneggiamo entità non consistenti
con la business logic. È buona norma non avere un costruttore vuoto se un’entità ha campi
obbligatori, altrimenti l’entità ha uno stato inconsistente quando andiamo a creare un’istanza
di quell’oggetto.
è meglio annotare i campi invece di fornire getter e setter.

Come gestire entità con molti campi obbligatori? Possiamo raggruppare alcuni campi in
entità. Possiamo utilizzare il pattern fluent interface che consente di restituire la stessa
classe che possiamo richiamare per fare altre operazioni come nell’esempio precedente.

Advanced constraints
Ci sono alcuni campi che possono essere obbligatori se uno manca. Ad esempio un conto
bancario deve avere uno scoperto oppure un account di riserva.

The builder pattern


● L'idea è quella di ottenere un oggetto completo, che soddisfi tutti i vincoli, prima che
altre parti del codice vi abbiano accesso;
● La complessità della costruzione dell'entità è nascosta da un altro oggetto, il
costruttore;
● Chi usa il costruttore non ha bisogno di vedere l'oggetto parzialmente costruito (e
non può vederlo).

Ora sappiamo creare entità valide, ma come assicurarci che le entità che sono oggetti
mutabili nel Drive-Domain Development, siano validi dopo i cambiamenti?

WRONG WAY
CORRECT WAY

Non dobbiamo condividere gli oggetti mutabili, altrimenti perdiamo il controllo sulla loro
validità. Il modo più sicuro è condividere i domini primitivi.
Se devi ritornare un oggetto mutabile, restituisci una sua copia.

Per quanto riguarda le collezioni, come le liste, non possiamo restituire l’entità perché è
mutabile, potremmo fare una copia ma è costoso ma è meglio codificare la logica aziendale,
come metodi per aggiungere o riordinare. Se vogliamo proprio restituire la lista potremmo
utilizzare un proxy, ma attenzione agli oggetti dentro alla lista, dobbiamo essere sicuri che
siano immutable? è sempre meglio fare una copia approfondita anche se è molto costosa.
Esercizi
Lezione 8
Reducing complexity of state
Controllare gli stati mutabili delle entità è difficile. Abbiamo bisogno di un pattern sicuro per
gestire le transazioni di stati delle entità.

Fino ad ora abbiamo visto metodi che funzionano per il single-thread, questi metodi hanno
problemi detti TOCTOU (Time-to-check to time-to-usage) in quanto possono essere
eseguiti in parallelo da un altro thread dove il check non sarebbe rispettato se la funzione
non soffrisse del problema.

Pattern per gestire le transizioni di stato delle entità:


● Partially immutable entities: qualsiasi cosa che ci aspettiamo che non cambi
dev’essere resa immutabile. Ad esempio se abbiamo una classe Ordine dove
abbiamo un campo customer_id, il customer_id non dovrebbe cambiare perché è
stupido assegnare quell’ordine ad un altro customer_id. In questo modo si rendono le
entità parzialmente immutabili;
● Entity state objects: abbiamo delle transazioni che cambiano il nostro stato.

Gli stati sono rappresentati esplicitamente, quindi possiamo testarli in maniera


unitaria.
Nel Multi-thread environments va bene condividere i domain primitives (immutable
objects) mentre per gli oggetti mutabili alcuni metodi vanno sincronizzati e possiamo avere
problemi di inconsistenza, deadlock ecc.
● Entity snapshots: l’entità non è rappresentata da una classe mutabile, ma
utilizziamo degli snapshot immutabili dell’entità. Lo snapshot non dev’essere per
forza una foto dell’intera entità, anche giusto la porzione che ci interessa. Se ho uno
snapshot e voglio apportare delle modifiche creo un metodo che prende lo snapshot
e il parametro che voglio modificare. Se lo snapshot rappresenta ancora l’entità,
ovvero un check che verifica che il parametro che vogliamo cambiare è uguale siano
nello snapshot che nell’entità, allora possiamo procedere al cambiamento;
● Entity relay: pattern per maneggiare entità con molti stati. L’idea è quella di
identificare le fasi di vita dell’entità del dominio. Ogni fase è quindi rappresentata da
una nuova entità. Ogni cambiamento comporta un cambiamento di entità.
Nella seconda immagine possiamo cercare dei gruppi che rappresentano degli stati
delle fasi.
Lezione 9
Nulla
Nulla

Lezione 10
Handling failures securely
Quando progettiamo un software dobbiamo pensare alla possibilità che gli utenti falliscono.
Le eccezioni devono restituire un messaggio perché e dove c’è stato il problema.
Esistono due tipi di eccezioni che vanno gestite separatamente, le eccezioni della business
logic e le eccezioni tecniche. Le eccezioni vanno gestite separatamente per capire
immediatamente in che tipo di eccezione ci troviamo senza riconoscere il messaggio
stampato.

Se abbiamo un’eccezione business logic sconosciuta, che non dovrebbe esistere, runniamo
un’eccezione tecnica. Le eccezioni non dovrebbero includere dati sensibili.

I fallimenti sono un risultato naturale e atteso di tutto ciò che facciamo, è giusto trattarli come
eccezioni? Dipende se il risultato è eccezionale o meno.
Progettare per l’availability
Non vogliamo che la nostra applicazione o il nostro servizio non siano disponibili, tuttavia
può capitare che la nostra applicazione non sia disponibile oppure non siamo in grado di
soddisfare tutte le richieste. è sempre meglio cercare di informare l’utente che il server è
occupato piuttosto che lasciarlo in attesa.

Questo è lo schema che dovremmo utilizzare per le richieste. Iniziamo con il sistema chiuso
e contiamo le richieste che falliscono. Se ne falliscono troppe mettiamo il sistema aperto.
Dopo un po’ di tempo elaboriamo alcune richieste ed in base al risultato decidiamo se aprire
o chiudere il ciclo.

Gestire i dati in input


I dati in input sono spesso sporchi ed è meglio non tentare di ripararli perché potremmo
subire alcuni attacchi.
Lezione 11
TODO
Bla

Lezione 12
TODO
Bla

Lezione 13
TODO
Bla

Lezione 14
TODO
Bla

Lezione 15
TODO
Bla
Lezione 16
TODO
Bla

Lezione 17
TODO
Bla

Lezione 18
TODO
Bla

Lezione 19
TODO
Bla

Lezione 20
TODO
Bla

Lezione 21
TODO
Bla

Lezione 22
TODO
Bla

Lezione 23
TODO
Bla

Lezione 24
TODO
Bla

Potrebbero piacerti anche