This shows you the differences between two versions of the page.
|
poo-ca-cd:laboratoare:programare-avansata-java [2026/01/11 23:21] florian_luis.micu [Observații importante] |
poo-ca-cd:laboratoare:programare-avansata-java [2026/01/12 01:22] (current) florian_luis.micu [[Optional] Software Development Methodologies] |
||
|---|---|---|---|
| Line 7: | Line 7: | ||
| =====Obiective===== | =====Obiective===== | ||
| - | =====Serializare și Deserializare===== | + | Scopul acestui laborator este introducerea studenților în concepte mai avansate care permit crearea framework-urilor și a aplicațiilor enterprise. |
| + | |||
| + | Aspectele urmărite sunt: | ||
| + | * înțelegerea conceptelor de testare. | ||
| + | * utilizarea corectă a mecanismului de reflection. | ||
| + | * exersarea serializărilor și deserealizărilor. | ||
| + | * implementarea și utilizarea corectă a adnotărilor. | ||
| + | * exersarea folosirii aserților. | ||
| + | * familiarizarea cu dependențe populare cum ar fi JUnit, Mockito, Jackson. | ||
| + | |||
| + | Aspectele **bonus** urmărite sunt: | ||
| + | * înțelegerea mecanismelor de logging. | ||
| + | * aprofundarea metodologiilor de dezvoltare software. | ||
| + | * Diferența dintre getClass() și instanceof. | ||
| + | * Organizarea memoriei pentru moștenire în Java. | ||
| + | |||
| + | <note warning> | ||
| + | * În acest laborator există mai multe secțiuni marcate **[Optional]**. Aceste secțiuni cuprind informații **bonus** care vă pot fi prezentate în **timpul laboratorului** sau pe care le puteți aprofunda **în afara** acestuia, ele nefiind necesare pentru laboratoarele viitoare sau pentru teme. | ||
| + | * De asemenea, veți întâlni câteva secțiuni marcate **[Nice to know]**. Vă recomandăm ca acestea să aibă **prioritate** în parcurgerea secțiunilor de tip **[Optional]**, deoarece vă pot oferi informații bonus care să fie și foarte probabil utile pentru **teme** sau **laboratoare viitoare**. | ||
| + | </note> | ||
| + | |||
| + | =====🔄 Serializare și Deserializare===== | ||
| ====Ce este serializarea?==== | ====Ce este serializarea?==== | ||
| Line 174: | Line 195: | ||
| ===De ce este Jackson preferat în aplicațiile moderne?=== | ===De ce este Jackson preferat în aplicațiile moderne?=== | ||
| - | De ce este Jackson preferat în aplicațiile moderne? | ||
| * JSON este lizibil și ușor de debugat, | * JSON este lizibil și ușor de debugat, | ||
| * este interoperabil cu alte limbaje, | * este interoperabil cu alte limbaje, | ||
| Line 339: | Line 359: | ||
| </code> | </code> | ||
| - | =====Adnotări în Java===== | + | =====🏷️ Adnotări în Java===== |
| ====Ce sunt adnotările?==== | ====Ce sunt adnotările?==== | ||
| Line 594: | Line 614: | ||
| - | =====Reflection în Java===== | + | =====🪞 Reflection în Java===== |
| ====Ce este Reflection?==== | ====Ce este Reflection?==== | ||
| Line 783: | Line 803: | ||
| - | =====Assertions===== | + | =====🔍 Assertions===== |
| ====Ce sunt assertions?==== | ====Ce sunt assertions?==== | ||
| Line 844: | Line 864: | ||
| - | =====Unit Testing===== | + | =====🔬 Unit Testing===== |
| ====Ce este Unit Testing?==== | ====Ce este Unit Testing?==== | ||
| Line 992: | Line 1012: | ||
| </note> | </note> | ||
| - | =====Integration Testing & Mocking===== | + | =====🧪 Integration Testing & Mocking===== |
| ====Ce este Integration Testing?==== | ====Ce este Integration Testing?==== | ||
| Line 1132: | Line 1152: | ||
| * când tipul nu e clar din context | * când tipul nu e clar din context | ||
| </note> | </note> | ||
| + | |||
| + | =====[Nice to know] 🪵 Logging în Java ===== | ||
| + | |||
| + | ==== Ce este logging-ul? ==== | ||
| + | |||
| + | Logging-ul reprezintă mecanismul prin care o aplicație înregistrează informații despre: | ||
| + | * execuția codului | ||
| + | * evenimente importante | ||
| + | * erori sau situații neașteptate | ||
| + | |||
| + | Spre deosebire de ''System.out.println'', logging-ul: | ||
| + | * poate fi configurat (nivel, format, destinație) | ||
| + | * poate fi dezactivat fără a modifica codul | ||
| + | * este standard în aplicații profesionale | ||
| + | |||
| + | ====De ce NU folosim System.out.println?==== | ||
| + | |||
| + | Instrucțiunea ''System.out.println'': | ||
| + | * nu are niveluri (info, warning, error) | ||
| + | * nu poate fi filtrat pe baza nivelelor | ||
| + | * nu este potrivit pentru producție | ||
| + | |||
| + | ====Logging standard în Java (java.util.logging)==== | ||
| + | |||
| + | Java oferă un mecanism de logging în JDK, fără biblioteci externe ''java.util.logging''. | ||
| + | |||
| + | Exemplu minimal: | ||
| + | <code java> | ||
| + | import java.util.logging.Logger; | ||
| + | |||
| + | public class Example { | ||
| + | private static final Logger logger = | ||
| + | Logger.getLogger(Example.class.getName()); | ||
| + | |||
| + | void run() { | ||
| + | logger.info("Application started"); | ||
| + | } | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | Niveluri de logging (cele mai uzuale) | ||
| + | |||
| + | * ''SEVERE'' / ''ERROR'' – erori critice | ||
| + | * ''WARNING'' – situații problematice | ||
| + | * ''INFO'' – informații generale | ||
| + | * ''FINE'' / ''DEBUG'' – detalii de execuție | ||
| + | |||
| + | <note important> Logging-ul NU trebuie să schimbe comportamentul aplicației, **doar să-l observe**. </note> | ||
| + | |||
| + | ====Logging folosind Log4j==== | ||
| + | |||
| + | Pe lângă mecanismul de logging din JDK (java.util.logging), în practică este foarte des întâlnită biblioteca Apache Log4j. | ||
| + | |||
| + | Log4j este: | ||
| + | * o bibliotecă externă de logging (nu face parte din JDK) | ||
| + | * mai flexibilă și mai configurabilă decât logging-ul standard din Java | ||
| + | * folosită frecvent în aplicații enterprise și framework-uri | ||
| + | |||
| + | Un exemplu de inițializare: | ||
| + | <code java> | ||
| + | import org.apache.logging.log4j.LogManager; | ||
| + | import org.apache.logging.log4j.Logger; | ||
| + | |||
| + | public class Example { | ||
| + | private static final Logger logger = | ||
| + | LogManager.getLogger(Example.class); | ||
| + | |||
| + | void run() { | ||
| + | logger.info("Application started"); | ||
| + | } | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | <note warning> Log4j a fost implicat în vulnerabilitatea **Log4Shell (2021)**, una dintre cele mai grave din istoria Java. Acest lucru NU înseamnă că logging-ul este periculos, ci că **bibliotecile trebuie actualizate și verificate pentru vulnerabilități**. În prezent, există utilitare care fac acest lucru automat cum ar fi [[https://snyk.io/|Snyk]]</note> | ||
| + | |||
| + | <note tip> | ||
| + | * ''java.util.logging'' → suficient pentru laborator și aplicații simple | ||
| + | * Log4j → standard de facto în aplicații mari | ||
| + | * ''System.out.println'' → nu este logging | ||
| + | </note> | ||
| + | |||
| + | =====[Optional] 🗺️ Software Development Methodologies===== | ||
| + | |||
| + | În urma paradigmei OOP, au fost concepute mai multe metodologii care pot augmenta performanța sau anumite abilități ale unui proiect conform necesităților. | ||
| + | |||
| + | De exemplu, **Data Oriented Design** (DOD) este o paradigmă care ajută programarea folosind obiecte prin folosirea **cache-ului**. Practic, clasele sunt refactorizate astfel încât să țină cont de mărimea cache-ului din procesor pentru a scădea drastic timpii de acces. Această paradigmă începe să fie destul de folosită în mediile în care viteza este importantă, cum ar fi programarea jocurilor video, drept urmare chiar și engine-ul Unity a fost rescris astfel încât să folosească DOD (găsiți articolul [[https://unity.com/dots|aici]]. | ||
| + | |||
| + | <note tip> | ||
| + | Vă recomandăm să parcurgeți secvențe din acest videoclip de la [[https://www.youtube.com/watch?v=yy8jQgmhbAU|CppCon]]. | ||
| + | </note> | ||
| + | |||
| + | O altă metodologie utilă este **Test Driven Development** (TDD) în care accentul este pus pe dezvoltarea testelor înainte de a dezvolta codul propriu-zis. Practic, după etapa de ideație, putem trece la crearea testelor care vor defini comportamentul corect al programului nostru, apoi vom dezvolta codul necesar pentru a putea trece cu succes peste testele scrise de noi. Puteți citi mai multe despre această abordare [[https://agilealliance.org/glossary/tdd/|aici]]. | ||
| + | |||
| + | De asemenea, o altă metodologie folosită este **Domain Driven Design** (DDD) care este o abordare de proiectare software în care structura aplicației este ghidată de domeniul de business, iar logica esențială este modelată prin concepte clare (entități, valori, agregate) definite împreună cu experți din domeniu, folosind un limbaj comun (ubiquitous language) pentru a menține codul aliniat cu realitatea problemei. Această abordare este detaliată în articolul scris de Redis [[https://redis.io/glossary/domain-driven-design-ddd/|aici]]. | ||
| + | =====Exerciții===== | ||
| + | |||
| + | <note tip> | ||
| + | Pentru exercițiile de mai jos va trebui să vă creați propriile proiecte Maven. Vă recomandăm să luați dependențele necesare de pe [[https://mvnrepository.com/repos/central|Maven Repository]], concret JUnit și Mockito. | ||
| + | |||
| + | De asemenea, vă recomandăm să parcurgeți documentația Mockito și JUnit sau să folosiți ghiduri de pe site-uri de specialitate cum ar fi [[https://www.baeldung.com/mockito-series|Baeldung Mockito series]]. | ||
| + | </note> | ||
| + | |||
| + | <note important> | ||
| + | Acest laborator nu va fi încărcat pe Devmind Code, deoarece va fi verificat manual de către laborantul vostru. | ||
| + | </note> | ||
| + | ====Task 1 – Unit Testing cu coverage ≥ 80% (6p)==== | ||
| + | |||
| + | Se dă următoarea clasă de producție, care modelează un serviciu simplu de procesare a comenzilor. Codul conține: | ||
| + | * ramificații (if) | ||
| + | * excepții | ||
| + | * assertions | ||
| + | * logică dependentă de input | ||
| + | |||
| + | <code java> | ||
| + | public class OrderService { | ||
| + | |||
| + | public double calculateTotal(double price, int quantity) { | ||
| + | assert price >= 0 : "Price must be non-negative"; | ||
| + | assert quantity > 0 : "Quantity must be positive"; | ||
| + | |||
| + | return price * quantity; | ||
| + | } | ||
| + | |||
| + | public double applyDiscount(double total, double discountPercent) { | ||
| + | if (discountPercent < 0 || discountPercent > 50) { | ||
| + | throw new IllegalArgumentException("Invalid discount"); | ||
| + | } | ||
| + | |||
| + | return total - (total * discountPercent / 100); | ||
| + | } | ||
| + | |||
| + | public String categorizeOrder(double total) { | ||
| + | if (total < 100) { | ||
| + | return "SMALL"; | ||
| + | } else if (total < 500) { | ||
| + | return "MEDIUM"; | ||
| + | } else { | ||
| + | return "LARGE"; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | public boolean isFreeShipping(double total) { | ||
| + | return total >= 200; | ||
| + | } | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | Scrieți teste unitare folosind JUnit 5 astfel încât: | ||
| + | * coverage-ul clasei să fie ≥ 80% | ||
| + | * toate ramurile importante să fie testate | ||
| + | * testele să fie clare, independente și deterministe | ||
| + | |||
| + | <note tip> | ||
| + | În industrie, testarea este importantă, iar o metrică consacrată în acest sens este ca 80% din cod să fie acoperit de teste. Pentru a verifica cât cod este acoperit de testele voastre puteți folosi [[https://www.jetbrains.com/help/idea/code-coverage.html|ghidul oficial IntelliJ]] sau să întrebați laborantul. | ||
| + | </note> | ||
| + | |||
| + | <note important> | ||
| + | Pentru a testa cât mai mult cod, trebuie să generați teste valide și invalide pentru codul dat, astfel încât să testați toate ramurile logice. | ||
| + | </note> | ||
| + | |||
| + | ====Task 2 - Integration Test + Mocking (4p)==== | ||
| + | |||
| + | Se dau următoarele clase: | ||
| + | <code java User.java> | ||
| + | public class User { | ||
| + | private final String name; | ||
| + | |||
| + | public User(String name) { | ||
| + | this.name = name; | ||
| + | } | ||
| + | |||
| + | public String getName() { | ||
| + | return name; | ||
| + | } | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | <code java UserRepository.java> | ||
| + | public interface UserRepository { | ||
| + | User findById(long id); | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | <code java UserService.java> | ||
| + | public class UserService { | ||
| + | |||
| + | private final UserRepository repository; | ||
| + | |||
| + | public UserService(UserRepository repository) { | ||
| + | this.repository = repository; | ||
| + | } | ||
| + | |||
| + | public String getUserName(long id) { | ||
| + | User user = repository.findById(id); | ||
| + | return user.getName(); | ||
| + | } | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | - Scrieți un test pentru UserService folosind Mockito. | ||
| + | - Mock-uiți UserRepository astfel încât: | ||
| + | * pentru id = 1, să returneze un User("Ana") | ||
| + | - Verificați că metoda getUserName(1) returnează "Ana". | ||
| + | | ||
| + | Puteți folosi ''var'' pentru: | ||
| + | * repository | ||
| + | * service | ||
| + | * rezultatul final | ||
| + | |||
| + | <note tip>Denumirea și scopul claselor de mai sus respectă un standard folosit de framework-ul Spring.</note> | ||
| + | |||
| + | ===== Resurse și link-uri utile ===== | ||
| + | * [[https://site.mockito.org/ | Mockito]] | ||
| + | * [[https://www.atlassian.com/continuous-delivery/software-testing/types-of-software-testing | Different types of software testing]] | ||
| + | * [[https://www.baeldung.com/java-logging-intro | Introduction to Java logging - Baeldung]] | ||
| + | * [[https://softwareengineering.stackexchange.com/questions/123956/why-should-i-use-reflection | Why should I use reflection and when? - StackOverflow]] | ||