Durante la scrittura del codice mantieni una scrittura ordinata, segui il format di coding ufficiale Google: Google Styleguide Java
Importante: usa la documentazione fino a Java SE 8 compreso, la puoi trovare qui
Warning
Il giorno dell'esame ovviamente non seguire tutti questi passaggi ma un alternativa piú "snella" che ti permetta di rientrare nelle 2 ore!
Personalmente io alleggerisco questa metodologia (1) evitando la creazione di myMain, breakCode e dataManipulation, li creo solo se saranno necessari, sul momento; (2) non copia-incollo i comandi del pdf nella javadoc, evito di fare lo pseudo-codice se non strettamente necessario (3) unisco la fase 3 e 4 in un solo step; (4) cerco di bucare il codice solo se mi avanza tempo; (5) non ottimizzo il codice a fine programma, anzi, eventualmente lo sporco se mi rende la vita piú facile; (6) rompo il vincolo DRY e KISS se necessario; (7) alla consegna mi limito solo a ricontrollare il pdf e le firme dei metodi e rimuovere breakCode e myMain (e gli eventuali file a loro relativi).
Copia lo scheletro e salvalo in un file bones.txt
interno al progetto
Crea un file txt todo.txt
interno al progetto dove annotare ció che ti viene in mente, la todo list e altro
Crea un package myTests
e myMethods
(o i nomi che preferisci) per, rispettivamente:
- Creare i tuoi main di testing del codice (
myMain.java
ebreakCode.java
in myTest) - Riunire i metodi di manipolazione dati (
dataManipulationMethods.java
in myMethods)
myMethods mettilo come sottopackage del package principale fornito dalla consegna, altrimenti non te lo legge (come specificato a inizio di ogni pdf)
Leggi il pdf diviso per parti
Ogni volta che inizi una parte dei requisiti:
- Sottolinea/evidenzia i relativi vincoli mentre leggi
- Copia e incolla le richieste del pdf nella javadoc del metodo a esse relativo (
/***/
) - Prepara i commenti multi riga per lo pseudo codice, per ogni metodo (
/**/
)
Fatti un idea generale di programma e abbozza velocemente su un foglio di carta una struttura generale del programma
Torna all'inizio del pdf e skimma ogni parte per generare i vari package, classi, attributi, getter e setter di base (Alt + S
)
- Metti gli attributi a
private/protected
, i metodi apublic
- Crea dei costruttori vuoti di default per ogni classe con costanti
static final
di default (utili per testare il codice velocemente in myTests) - Crea i metodi
toString()
,equals(Object o)
ecompareTo(Object o)
(nei test non vengono mai stampati gli oggeti direttamente)
package simplePackage;
import java.util.LinkedList;
public class SimpleClass {
public final static int CONSTANT_FOR_COMMON_ATTRIBUTE = 42; // il significato di tutto
public final static LinkedList<Boolean> DEFAULT_ATTRIBUTE_FOR_CHILDS = new LinkedList<Boolean>();
public final static String BEST_QUOTE = "DON'T PANIC!";
private int commonAttribute;
protected LinkedList<Boolean> attributeForChilds;
public SimpleClass() {
super();
commonAttribute = CONSTANT_FOR_COMMON_ATTRIBUTE;
attributeForChilds = DEFAULT_ATTRIBUTE_FOR_CHILDS;
attributeForChilds.addFirst(true);
}
public SimpleClass(int commonAttribute, LinkedList<Boolean> attributeForChilds) {
super();
this.commonAttribute = commonAttribute;
this.attributeForChilds = attributeForChilds;
}
public int getCommonAttribute() {
return commonAttribute;
}
public LinkedList<Boolean> getAttributeForChilds() {
return attributeForChilds;
}
public void setCommonAttribute(int commonAttribute) {
this.commonAttribute = commonAttribute;
}
public void setAttributeForChilds(LinkedList<Boolean> attributeForChilds) {
this.attributeForChilds = attributeForChilds;
}
public int compareTo(SimpleClass other) {
return other.commonAttribute - this.commonAttribute;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
SimpleClass other = (SimpleClass) obj;
return compareTo(other) > CONSTANT_FOR_COMMON_ATTRIBUTE;
}
@Override
public String toString() {
return BEST_QUOTE;
}
}
Per ogni parte del pdf:
- Prima si pianifica e dopo si scrive!
- Work smart, not hard! (Non ti dedicare a strutture dati - inutilmente - complicate ma cerca il modo piú veloce e intelligente di risolvere il problema)
- Individua quei metodi "simili" che sono riscrivibili come unico metodo (DRY)
- Inzia a creare il programma, per ogni metodo:
- Crea lo pseudocodice relativo (aiutandoti con carta e penna eventualmente) da inserire in cima (
/**/
) - Crea il codice, eventualmente commentando riga per riga (
//
) per i metodi piú complessi - Testa il loro funzionamento su myMain e con
Esempio.java
- Crea lo pseudocodice relativo (aiutandoti con carta e penna eventualmente) da inserire in cima (
- Debugga! Non importa quali siano le tue capacitá, se non sai debuggare imparalo subito!, all'esame sará fondamentale. Se non sai come debuggare su Eclipse puoi guardare questo video
- Segnati le cose da fare successivamente con
//TODO
e la window Tasks di Eclipse - (Avanzato) Usa git con Egit per fare una cronologia del progetto
Per farti un idea piú approfondita di come sono stati applicati questi punti nel concreto puoi dare un occhiata al mio codice in questa repo
/**
* Riceve come parametro
* l’email dell’utente da cercare
* e ritorna l’utente desiderato se registrato,
* null altrimenti
* */
public Utente cercaUtente(String email) {
/*
* Scorro la lista di utenti
* Controllo che l'email in scorrimento coincida con il parametro
* Se true: utente trovato, me lo salvo e lo restituisco
* Se false: non faccio nulla e continuo lo scorrimento del for
* */
Utente output = null;
for (Utente utente : utenti) {
String emailInLoop = utente.getEmail();
if (emailInLoop.equals(email)) {
output = utente;
}
}
return output;
}
Cerca di bucare il codice in BreakCode, anche qui mantieni una scrittua ordinata e dividi i vari test in metodi
package myTests;
import cluster.*;
public class BreakCode {
public static void main(String[] args) {
sopln("Creazione Cluster\n");
Cluster c = new Cluster(5, 10);
test1(c);
test2(c);
test3(c);
}
public static void test1(Cluster c) {
/* TEST PARTE 1 */
makeUsers(c);
describeUsers(c);
searchUsers(c);
}
public static void makeUsers(Cluster c) {
sopln(" * * * " + "Creazione utenti".toUpperCase() + " * * *\n");
//Creo un primo admin e testo di getter
UtenteAdmin u1 = c.registraUtente("[email protected]", "Fabio", "Garcea", "Password1", "19930917", "pub - Che schifo Python (mi dissocio)", "priv - ma poi chi é che fa ingegneria matematica in questo corso? Ragazzi fatevi vedere");
sopln("Creato utente admin: " + u1.getEmail());
sopln(u1.getNome());
sopln(u1.getCognome());
sopln(u1.getPassword());
sopln(u1.getDataNascita());
sopln(u1.getChiavePubblica());
sopln(u1.getChiavePrivata());
sopln();
// Creo un secondo admin
c.registraUtente("[email protected]", "Cristiano", "Ronaldo", "jesusChrist3", "20000101", "SHA-1-PUBKEY", "SHA-1-PRIV_KEY");
// Creo utenti standard
sopln("Creazione altri utenti (standard)...");
c.registraUtente("[email protected]", "Fabrizio", "Lamberti", "passWord2", "19800101");
c.registraUtente("[email protected]", "Lia", "Morra", "3passworD", "19850101");
c.registraUtente("[email protected]", "Guido", "Marchetto", "pass4woRd", "19850202");
// Genero un utente e provo a rifarlo ma con un tipo diverso
c.registraUtente("[email protected]", "Winston", "Churchill", "nukeBerlinN0W", "18901225");
c.registraUtente("[email protected]", "Winston", "Churchill", "nukeBerlinN0W", "18901225", "ThisKeyWillBeIgnored", "ThisOneToo");
c.registraUtente("[email protected]", "Elon", "Musk", "comicityIsLegalOnTwitterNow", "19850101", "DOGE101-PUB", "DOGE101-PRIV");
c.registraUtente("[email protected]", "Elon", "Muschio", "Selvaggi0", "19850101");
//Genero degli utenti con formati di email, password o dataNascita incompatibili
c.registraUtente("[email protected]", "Misato", "Katsuragi", "thekidlaroi", "19850101");
c.registraUtente("emailErrata", "Asuka", "Langley Soryu", "theK1dLaroi", "19850101");
c.registraUtente("eta@minorenne", "Rei", "Ayanami", "theK1dLaroi", "20200101");
sopln();
}
public static void sopln() {
sopln("");
}
public static void sopln(Object o) {
System.out.println(o);
}
}
- Crea algoritmi più snelli o semplici (DRY, KISS, SOLID)
- Risolvi le domande che ti sono rimaste (segnate in todo.txt)
- Effettua un backup esportando il file zip del progetto
- Rimetti le varie righe spezzate su una sola riga (per non avere problemi nei test)
- Rileggi il pdf per vedere se hai rispettato tutte le specifiche
- Ricontrolla che le firme dei metodi coincidano con lo scheletro (usa bones.txt del passo 1)
- Fai un ultimo run di BreakCode, myMain e Esempio
- Togli la roba inutile
- Commenti di troppo
- Metodi inutilzzati (non togliere i setter e getter inutilizzati, magari ti serviranno nella riconsegna)
- I file extra dove magari hai scritto e usato caratteri non riconosciuti
- Runna per l'ultimissima volta Esempio (unico main rimasto)
- Consegna
DRY, KISS & SOLID explained in Godot
-
Dont write duplicate code
- If code is repeated, put it inside a function (Code Refactor)
- It's NOT ok to repeat the code once or twice, it must NEVER be repeated, neather one time
- Less lines = Clean, Simple, Mantainable
-
The more you use DRY the more you are gonna see code duplication
General Rule: 200 lines per class, 20-30 per function, 20-50 per method (spaces and {} excluded)
OBJ: Making Code Isolation and Code Reusability
-
If you are thinking "What is going on? I cant follow this code" then you are breaking the KISS principle
-
If KISS is broken, refactor your code by trying alternatives
Note: (NOT by innesting it in functions - that's dry - but by creating new lean algorithms)
-
The more you use KISS the more you are gonna see complex code
OBJ: Untagling Complex Code in something readable
S: Single Responsibility
Each class should have one responsability in the code
Eventually you can break a class in smaller classes if it gets bigger (refactoring + class injection)
Each function should do one thing only in the code
Eventually you can break your function in other smaller functions (refactoring + function injection)
Basically every block of code should have one and one porpuse only, aiming to solve it
O: Open to extensions, Closed to modifications
Each piece of code you develop should let others to implement it or extend it in other cases
but you have to make a good piece of code that works so well it doesn't need to be modified in order to implement the new extensions
Basically you have to make a "generic" code that works in a generic way so your code can be re-used easily
L: Liskov Sobstitution
If a certain piece of code works for a group of object of type T then
it should perfectly work even with a group of objects of type S (where S is a child of T)
If you need to override some parent's functions then make sure the parameters (inputs)
and the returned values (outputs) are of the same type and respect the original rules
If you need to broke this last rule then just make a new function (eventually with a similar name)
Basically just make sure your child classes are 100% compatible with code that uses parent class
I: Interface Segregation
Programmers should not be forced to depend upon interfaces (classes, functions etc) that they don't use
what it means is that it should never happen that you will have to "work" or "think about" how to resolve a certain
interface that you wont ever use.
D: Dependency Inversion
High level classes/modules should not depend on low level classes/modules, both shoul depend on abstractions
Abstractions should not depend on details, details should depend on abstractions.
- Refactoring = Change the code of a program without changing its behaviour
- Injection = Making classes/functions/elements only in order to be used into other classes/functions