
Learning Log #5: Pierwszy większy projekt w Java – od pomysłu do działającej aplikacji
Wtorek, 3 czerwca, 22:47. Ostatni test przechodzi. Zielone checkmarki w konsoli. Aplikacja działa.
Mój pierwszy większy projekt w Java jest GOTOWY.
Patrzę na ekran i czuję… dumę? Ulgę? Niedowierzanie? Wszystko naraz.
5 tygodni temu to był tylko pomysł w Notion: „Zbuduj coś prawdziwego, nie tylko ćwiczenia z kursu.” Dzisiaj mam 47 klas, 2847 linii kodu i działającą aplikację do zarządzania terapiami mojego dziecka.
Pierwszy projekt w Java to przełom. To moment, gdy przestajesz być „osobą, która się uczy” i stajesz się „osobą, która buduje”. To jest ogromna różnica.
Dziś opowiem Wam całą historię – od pomysłu, przez architekturę, wyzwania techniczne, do finału. I najważniejsze: co czułam kończąc pierwszy prawdziwy projekt jako programistka.
Skąd pomysł – dlaczego akurat aplikacja do terapii?
Problem, który widziałam codziennie
Moja rzeczywistość:
- 8-9 godzin terapii tygodniowo (SI, logopedia, pedagogika, TUS)
- 3 różne ośrodki
- 5 terapeutów
- Niekończące się faktury, zestawienia kosztów, raporty dla NFZ
- Excel, który się sypie co miesiąc
Próbowałam gotowych rozwiązań:
- Kalendarz Google – za prosty (tylko daty, bez kosztów)
- Excel – chaotyczny, gubię dane
- Aplikacje do zarządzania zdrowiem – zbyt ogólne, nie dla terapii
Pomyślałam: „Co jeśli zbuduję własną aplikację?”
Punkt zwrotny – rozmowa z instruktorem kursu
Napisałam na Discord Zajavka:
„Skończyłam podstawy kursu. Co dalej? Spring? JavaScript?”
Instruktor odpowiedział:
„Przed Springiem zbuduj JEDEN solidny projekt w czystej Javie. Coś co rozwiązuje prawdziwy problem. Pokaże Ci jak projektować aplikacje, nie tylko pisać kod.”
I kliknęło.
Pierwszy projekt w Java – planowanie
Tydzień 1: Research i wymyślanie funkcjonalności
Pytania, które sobie zadałam:
- Co aplikacja MUSI umieć? (MVP – Minimum Viable Product)
- Dodawanie sesji terapii
- Przechowywanie informacji o terapeutach i ośrodkach
- Kalkulacja kosztów miesięcznych
- Generowanie raportów
- Co byłoby FAJNE, ale nie konieczne? (v2.0)
- Przypomnienia o sesjach
- Statystyki roczne
- Export do PDF
- Integracja z kalendarzem
- Czego NIE potrzebuję? (scope control)
- GUI (graficzny interfejs) – na razie konsola wystarczy
- Baza danych – na razie pliki tekstowe
- Multi-user – tylko ja używam
Decyzja: Buduję wersję konsolową z podstawowymi funkcjami. GUI później.
Tydzień 2: Architektura – najpierw plan, potem kod
Błąd początkujących: Otwieram IDE i zaczynam pisać kod bez planu.
Lepsze podejście: Planuję strukturę na papierze.
Moja architektura – diagram klas:
MAIN ENTITIES (główne encje):
TherapySession (Sesja terapii)
├── sessionId: String
├── therapyType: TherapyType (enum)
├── therapist: Therapist
├── dateTime: LocalDateTime
├── duration: int (minuty)
├── cost: BigDecimal
├── paid: boolean
├── notes: String
Therapist (Terapeuta)
├── therapistId: String
├── name: String
├── specialization: String
├── phone: String
├── email: String
├── hourlyRate: BigDecimal
TherapyCenter (Ośrodek terapeutyczny)
├── centerId: String
├── name: String
├── address: Address
├── phone: String
├── therapists: List<Therapist>
TherapyType (Typ terapii - ENUM)
├── SI (Integracja sensoryczna)
├── SPEECH (Logopedia)
├── PEDAGOGY (Pedagogika)
├── EARLY_INTERVENTION (Wczesne wspomaganie)
SERVICES (serwisy – logika biznesowa):
TherapySessionService
├── addSession()
├── updateSession()
├── deleteSession()
├── findSessionById()
├── getAllSessions()
├── getSessionsByMonth()
├── getSessionsByTherapist()
ReportService
├── generateMonthlyReport()
├── calculateTotalCost()
├── calculateCostByType()
├── generateYearlyStatistics()
PaymentService
├── markAsPaid()
├── getUnpaidSessions()
├── getTotalUnpaid()
REPOSITORIES (dostęp do danych):
FileRepository<T>
├── save(T entity)
├── findById(String id)
├── findAll()
├── delete(String id)
├── update(T entity)
UTILITIES (narzędzia pomocnicze):
DateUtils - formatowanie dat
ValidationUtils - walidacja danych
FileUtils - operacje na plikach
Dlaczego taka struktura?
Podział odpowiedzialności:
- Entities = Dane (co przechowujemy)
- Services = Logika (co robimy z danymi)
- Repositories = Dostęp (jak zapisujemy/odczytujemy)
- UI = Interfejs (jak użytkownik widzi)
Efekt: Jeśli zmienię sposób zapisywania (z plików na bazę danych) – zmieniam tylko Repository. Services i Entities pozostają bez zmian.
Tydzień 3-4: Implementacja – pierwszy kod
Zaczynanie od Entity
TherapySession.java – pierwsza klasa:
java
public class TherapySession {
private String sessionId;
private TherapyType therapyType;
private Therapist therapist;
private LocalDateTime dateTime;
private int durationMinutes;
private BigDecimal cost;
private boolean paid;
private String notes;
// Constructor
public TherapySession(String sessionId, TherapyType therapyType,
Therapist therapist, LocalDateTime dateTime,
int durationMinutes, BigDecimal cost) {
this.sessionId = sessionId;
this.therapyType = therapyType;
this.therapist = therapist;
this.dateTime = dateTime;
this.durationMinutes = durationMinutes;
this.cost = cost;
this.paid = false; // domyślnie nieopłacone
}
// Getters and setters
public String getSessionId() { return sessionId; }
public TherapyType getTherapyType() { return therapyType; }
// ... itd
// Business methods
public void markAsPaid() {
this.paid = true;
}
public boolean isInMonth(int year, int month) {
return dateTime.getYear() == year
&& dateTime.getMonthValue() == month;
}
@Override
public String toString() {
return String.format("%s | %s | %s | %.2f zł | %s",
dateTime.format(DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm")),
therapyType,
therapist.getName(),
cost,
paid ? "OPŁACONE" : "DO ZAPŁATY"
);
}
}
Co się nauczyłam:
- BigDecimal dla pieniędzy (nie double! – problemy z precyzją)
- LocalDateTime dla dat (lepsze niż Date)
- Enum dla typów terapii (type-safe, nie String)
- Business methods w encji (markAsPaid, isInMonth)
Wzorzec repozytorium – pierwsza abstrakcja
Problem: Jak zapisywać dane?
Opcje:
- Baza danych (za trudne na start)
- Pliki tekstowe (proste, ale jak czytać/zapisywać?)
Rozwiązanie: Wzorzec repozytorium z plikami JSON
FileRepository.java – generyczny repozytorium:
java
public class FileRepository<T> {
private final String filePath;
private final Class<T> entityClass;
private final ObjectMapper objectMapper; // Jackson dla JSON
public FileRepository(String filePath, Class<T> entityClass) {
this.filePath = filePath;
this.entityClass = entityClass;
this.objectMapper = new ObjectMapper()
.registerModule(new JavaTimeModule()); // dla LocalDateTime
}
public void save(T entity) throws IOException {
List<T> entities = findAll();
entities.add(entity);
writeToFile(entities);
}
public List<T> findAll() throws IOException {
File file = new File(filePath);
if (!file.exists()) {
return new ArrayList<>();
}
return objectMapper.readValue(file,
objectMapper.getTypeFactory()
.constructCollectionType(List.class, entityClass)
);
}
public Optional<T> findById(String id) throws IOException {
return findAll().stream()
.filter(e -> getId(e).equals(id))
.findFirst();
}
public void update(T entity) throws IOException {
List<T> entities = findAll();
String id = getId(entity);
entities.removeIf(e -> getId(e).equals(id));
entities.add(entity);
writeToFile(entities);
}
public void delete(String id) throws IOException {
List<T> entities = findAll();
entities.removeIf(e -> getId(e).equals(id));
writeToFile(entities);
}
private void writeToFile(List<T> entities) throws IOException {
objectMapper.writerWithDefaultPrettyPrinter()
.writeValue(new File(filePath), entities);
}
// Reflection do wyciągnięcia ID
private String getId(T entity) {
try {
Method method = entity.getClass().getMethod("getSessionId");
return (String) method.invoke(entity);
} catch (Exception e) {
throw new RuntimeException("Entity must have getSessionId method", e);
}
}
}
Co się nauczyłam:
- Generics (
<T>) – jeden magazyn dla różnych encji - Jackson ObjectMapper – serialization (proces przekształcania obiektów, tj. instancji określonych klas) do JSON
- Reflection (mechanizm, który umożliwia na odczyt i modyfikację informacji o klasach) – wyciąganie ID dynamicznie
- Exception handling (Obsługa wyjątków )- IOException musi być obsłużone
Service layer – logika biznesowa
TherapySessionService.java:
java
public class TherapySessionService {
private final FileRepository<TherapySession> repository;
public TherapySessionService() {
this.repository = new FileRepository<>(
"data/therapy_sessions.json",
TherapySession.class
);
}
public void addSession(TherapySession session) {
try {
// Walidacja
if (session.getCost().compareTo(BigDecimal.ZERO) <= 0) {
throw new IllegalArgumentException("Koszt musi być > 0");
}
if (session.getDateTime().isAfter(LocalDateTime.now())) {
System.out.println("UWAGA: Sesja w przyszłości");
}
repository.save(session);
System.out.println("✓ Dodano sesję: " + session);
} catch (IOException e) {
System.err.println("Błąd zapisu: " + e.getMessage());
}
}
public List<TherapySession> getSessionsByMonth(int year, int month) {
try {
return repository.findAll().stream()
.filter(s -> s.isInMonth(year, month))
.sorted(Comparator.comparing(TherapySession::getDateTime))
.toList();
} catch (IOException e) {
System.err.println("Błąd odczytu: " + e.getMessage());
return new ArrayList<>();
}
}
public void markSessionAsPaid(String sessionId) {
try {
Optional<TherapySession> session = repository.findById(sessionId);
if (session.isPresent()) {
session.get().markAsPaid();
repository.update(session.get());
System.out.println("✓ Oznaczono jako opłacone");
} else {
System.out.println("✗ Nie znaleziono sesji");
}
} catch (IOException e) {
System.err.println("Błąd: " + e.getMessage());
}
}
}
Co się nauczyłam:
- Walidacja danych (sprawdzanie przed zapisem)
- User feedback (komunikaty co się dzieje)
- Error handling (try-catch, komunikaty błędów)
- Stream API dla filtrowania i sortowania
Report Service – generowanie raportów
To była najtrudniejsza część.
ReportService.java:
java
public class ReportService {
private final TherapySessionService sessionService;
public void generateMonthlyReport(int year, int month) {
List<TherapySession> sessions =
sessionService.getSessionsByMonth(year, month);
if (sessions.isEmpty()) {
System.out.println("Brak sesji w tym miesiącu");
return;
}
System.out.println("=".repeat(80));
System.out.println("RAPORT MIESIĘCZNY: " + month + "/" + year);
System.out.println("=".repeat(80));
// Grupowanie po typie terapii
Map<TherapyType, List<TherapySession>> byType = sessions.stream()
.collect(Collectors.groupingBy(TherapySession::getTherapyType));
// Podsumowanie per typ
byType.forEach((type, typeSessions) -> {
int count = typeSessions.size();
int totalMinutes = typeSessions.stream()
.mapToInt(TherapySession::getDurationMinutes)
.sum();
BigDecimal totalCost = typeSessions.stream()
.map(TherapySession::getCost)
.reduce(BigDecimal.ZERO, BigDecimal::add);
long paidCount = typeSessions.stream()
.filter(TherapySession::isPaid)
.count();
System.out.printf("\n%s:\n", type);
System.out.printf(" Liczba sesji: %d\n", count);
System.out.printf(" Całkowity czas: %dh %dmin\n",
totalMinutes / 60, totalMinutes % 60);
System.out.printf(" Całkowity koszt: %.2f zł\n", totalCost);
System.out.printf(" Opłacone: %d/%d\n", paidCount, count);
});
// Suma totalna
BigDecimal grandTotal = sessions.stream()
.map(TherapySession::getCost)
.reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal unpaid = sessions.stream()
.filter(s -> !s.isPaid())
.map(TherapySession::getCost)
.reduce(BigDecimal.ZERO, BigDecimal::add);
System.out.println("\n" + "=".repeat(80));
System.out.printf("SUMA CAŁKOWITA: %.2f zł\n", grandTotal);
System.out.printf("DO ZAPŁATY: %.2f zł\n", unpaid);
System.out.println("=".repeat(80));
}
}
```
**Output przykładowy:**
```
================================================================================
RAPORT MIESIĘCZNY: 5/2026
================================================================================
SI:
Liczba sesji: 8
Całkowity czas: 8h 0min
Całkowity koszt: 600.00 zł
Opłacone: 8/8
SPEECH:
Liczba sesji: 8
Całkowity czas: 6h 0min
Całkowity koszt: 520.00 zł
Opłacone: 6/8
PEDAGOGY:
Liczba sesji: 4
Całkowity czas: 4h 0min
Całkowity koszt: 240.00 zł
Opłacone: 4/4
================================================================================
SUMA CAŁKOWITA: 1360.00 zł
DO ZAPŁATY: 130.00 zł
================================================================================
Co się nauczyłam:
- Collectors.groupingBy() – grupowanie strumieni
- Reduce dla sumowania BigDecimal
- String formatting (printf)
- Prezentacja danych (czytelny output)
Tydzień 5: UI i finiszowanie
Interfejs konsolowy – prosty, ale funkcjonalny
MainMenu.java:
java
public class MainMenu {
private final Scanner scanner;
private final TherapySessionService sessionService;
private final ReportService reportService;
public void run() {
while (true) {
displayMenu();
int choice = getChoice();
switch (choice) {
case 1 -> addSession();
case 2 -> listSessions();
case 3 -> markAsPaid();
case 4 -> generateReport();
case 5 -> {
System.out.println("Do widzenia!");
return;
}
default -> System.out.println("Nieprawidłowy wybór");
}
}
}
private void displayMenu() {
System.out.println("\n" + "=".repeat(50));
System.out.println("SYSTEM ZARZĄDZANIA TERAPIAMI");
System.out.println("=".repeat(50));
System.out.println("1. Dodaj sesję terapii");
System.out.println("2. Pokaż sesje (obecny miesiąc)");
System.out.println("3. Oznacz jako opłacone");
System.out.println("4. Generuj raport miesięczny");
System.out.println("5. Wyjście");
System.out.print("\nWybór: ");
}
private void addSession() {
System.out.println("\n=== NOWA SESJA ===");
// Wybór typu terapii
System.out.println("Typ terapii:");
TherapyType[] types = TherapyType.values();
for (int i = 0; i < types.length; i++) {
System.out.printf("%d. %s\n", i + 1, types[i]);
}
int typeChoice = scanner.nextInt() - 1;
TherapyType type = types[typeChoice];
// Wybór terapeuty (z listy wcześniej dodanych)
Therapist therapist = selectTherapist();
// Data i czas
System.out.print("Data (dd.MM.yyyy): ");
String dateStr = scanner.next();
System.out.print("Godzina (HH:mm): ");
String timeStr = scanner.next();
LocalDateTime dateTime = parseDateTime(dateStr, timeStr);
// Czas trwania
System.out.print("Czas trwania (minuty): ");
int duration = scanner.nextInt();
// Koszt
System.out.print("Koszt (zł): ");
BigDecimal cost = scanner.nextBigDecimal();
// Utworzenie sesji
TherapySession session = new TherapySession(
UUID.randomUUID().toString(),
type,
therapist,
dateTime,
duration,
cost
);
sessionService.addSession(session);
}
}
Co się nauczyłam:
- Scanner dla input użytkownika
- Menu loop (while true + switch)
- UUID dla unikalnych ID
- User experience (komunikaty, formatowanie)
Wyzwania techniczne – co było najtrudniejsze
1. Serializacja LocalDateTime do JSON
Problem:
java
Exception: Cannot serialize LocalDateTime
Rozwiązanie:
java
ObjectMapper mapper = new ObjectMapper()
.registerModule(new JavaTimeModule())
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
Lekcja: Jackson potrzebuje dodatkowych modułów dla Java 8 Date/Time API.
2. BigDecimal arytmetyka
Problem:
java
BigDecimal total = cost1 + cost2; // BŁĄD! Nie można + dla BigDecimal
Rozwiązanie:
java
BigDecimal total = cost1.add(cost2);
Lekcja: BigDecimal to immutable (niemodyfikowalny), używaj metod (.add, .subtract, .multiply)
3. File I/O exceptions
Problem: Aplikacja crashuje gdy plik nie istnieje.
Rozwiązanie:
java
public List<T> findAll() throws IOException {
File file = new File(filePath);
if (!file.exists()) {
// Utwórz pusty plik
file.getParentFile().mkdirs();
file.createNewFile();
writeToFile(new ArrayList<>());
return new ArrayList<>();
}
return objectMapper.readValue(file, ...);
}
Lekcja: Zawsze sprawdzaj czy plik/folder istnieje przed czytaniem.
4. Null handling w Optional
Problem:
java
TherapySession session = repository.findById(id); // może null
session.markAsPaid(); // NullPointerException!
Rozwiązanie:
java
Optional<TherapySession> sessionOpt = repository.findById(id);
if (sessionOpt.isPresent()) {
sessionOpt.get().markAsPaid();
} else {
System.out.println("Nie znaleziono");
}
// Lub functional style:
sessionOpt.ifPresent(TherapySession::markAsPaid);
```
**Lekcja:** Optional to explicite "może być null", obsługuj zawsze.
## Statystyki projektu - liczby
**Czas pracy:** 5 tygodni (kwiecień-maj 2026)
- Tydzień 1: Planowanie (10h)
- Tydzień 2: Architektura (8h)
- Tydzień 3-4: Implementacja (25h)
- Tydzień 5: UI + testy (12h)
- **Total: ~55 godzin**
**Kod:**
- **47 klas** (entities, services, repositories, utils, UI)
- **2847 linii kodu** (bez komentarzy)
- **89 metod** (średnio 32 linie/klasa)
- **23 pliki testowe** (JUnit tests)
**Biblioteki użyte:**
- Jackson (JSON serialization)
- JUnit 5 (testy jednostkowe)
- SLF4J + Logback (logging)
**Struktura folderów:**
```
therapy-manager/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ ├── com.therapy/
│ │ │ │ ├── entity/
│ │ │ │ ├── service/
│ │ │ │ ├── repository/
│ │ │ │ ├── util/
│ │ │ │ └── ui/
│ │ └── resources/
│ └── test/
│ └── java/
├── data/ (JSON files)
├── pom.xml (Maven dependencies)
└── README.md
Co czułam finiszując projekt
3 czerwca, 22:47 – ostatni test przechodzi
Uczucia w tym momencie:
1. Niedowierzanie „To naprawdę działa? Ja to zbudowałam?”
5 miesięcy temu nie znałam Javy. Dzisiaj mam działającą aplikację z 47 klasami.
2. Duma Pokazałam partnerowi: „Patrz, to dodaje sesję, to generuje raport…”
On: „Zrobiłaś TO?! To jest niesamowite!”
Ja: wzruszenie (szczęśliwe łzy)
3. Ulga Mogłam odpuścić 100 razy. „Za trudne”, „Nie dam rady”, „Może później”.
Ale nie odpuściłam. I skończyłam.
4. Więcej… To był tylko początek. Już myślałam: „Co dalej? GUI? Baza danych? Spring?”
Perspektywa – co projekt zmienił
Przed projektem:
- „Programowanie to nauka składni i algorytmów”
- „Projekty to coś dla ekspertów”
- „Ja tylko uczę się z tutoriali”
Po projekcie:
- „Programowanie to rozwiązywanie problemów”
- „Projekty to jedyny sposób, żeby naprawdę się nauczyć”
- „Ja BUDUJĘ, nie tylko uczę się”
Mentalna zmiana: Od „osoby która się uczy” do „programistki”.
Co bym zrobiła inaczej
1. Testy od początku, nie na końcu
Zrobiłam: Napisałam kod, potem testy.
Lepiej: TDD (Test-Driven Development) – testy najpierw, kod potem.
Dlaczego: Łatwiej refaktorować, gdy masz testy.
2. Mniejsze commity do Git
Zrobiłam: Wielkie commity „Added 10 classes”
Lepiej: Małe, atomowe commity „Add TherapySession entity”, „Add FileRepository”
Dlaczego: Łatwiej wrócić do poprzedniej wersji.
3. Więcej loggingu
Zrobiłam: System.out.println() wszędzie
Lepiej: SLF4J logger z poziomami (DEBUG, INFO, ERROR)
Dlaczego: Łatwiejszy debugging na produkcji.
4. Dokumentacja w trakcie, nie po
Zrobiłam: Dokumentacja README na końcu (zapomniałam połowę decyzji)
Lepiej: Notatki w Notion podczas budowania
Dlaczego: Świeża pamięć = lepsza dokumentacja.
Co dalej – plany na projekt
✅Wersja 1.0 (zrobione):
- Konsolowy interface
- JSON file storage
- Podstawowe raporty
Wersja 2.0 (czerwiec-lipiec):
- GUI (JavaFX) – graficzny interfejs
- Eksport raportów do PDF
- Charts (wykresy kosztów)
Wersja 3.0 (sierpień-wrzesień):
- Baza danych (PostgreSQL zamiast JSON)
- Multi-user (mąż też może dodawać sesje)
- Web interface (może Spring Boot?)
Ale najpierw: Przerwa. Odpoczynek. Perspektywa.
Nauki z pierwszego projektu w Java
Techniczne:
✅ OOP design – jak projektować klasy i relacje
✅ Wzorce projektowe – repozytorium, warstwa usług, wstrzykiwanie zależności
✅ File I/O – czytanie/zapis plików, JSON serializacja
✅ Kolekcje i strumienie – filtrowanie, grupowanie, redukcja
✅ Obsługa wyjątków – try-catch, niestandardowe wyjątki
✅ Testing – JUnit, pokrycie testowe
Nietechniczne (ważniejsze!):
✅ Ukończenie > Perfekcja – lepiej skończony prosty projekt niż nie skończony perfekcyjny
✅ Małe kroki – 1h dziennie przez 5 tygodni > 10h przez 1 dzień
✅ Realne problemy – budowanie czegoś co rozwiązuje własny problem = motywacja
✅ Liczy się pęd – 1 dzień przerwy OK, 3 dni = trudno wrócić
✅ Świętuj zwycięstwa – skończony projekt = osiągnięcie, świętuj to!
FAQ – pierwszy projekt w Java
Czy potrzebuję skończyć cały kurs przed projektem?
NIE. Ja zaczęłam projekt po:
- Podstawach składni (zmienne, pętle, warunki)
- OOP (klasy, obiekty, dziedziczenie)
- Collections (List, Map, Set)
- Podstawach Streams
Reszta nauczyłam się w trakcie projektu (JSON, File I/O, design patterns).
Ile czasu dziennie pracowałaś?
Średnio: 1.5h dziennie (10-15h tygodniowo)
Rozłożenie:
- Popołudnia: 1h (14:00-15:00)
- Wieczory: 30 min (21:30-22:00) – gdy energia była
Weekendy: 3-4h (sobota rano, partner z dziećmi)
Jak wybrać dobry projekt dla początkujących?
3 kryteria:
- Rozwiązuje TWÓJ problem – motywacja wewnętrzna
- Zakres realistyczny – zrobisz w 4-6 tygodni
- Trochę za trudny – uczysz się nowego, ale nie przytłaczający
Przykłady dobrych pierwszych projektów:
- Todo list manager (klasyk, ale działa)
- Expense tracker (śledzenie wydatków)
- Library manager (zarządzanie książkami)
- Habit tracker (śledzenie nawyków)
- Recipe organizer (przepisy kulinarne)
Zły projekt: „Zbuduję Facebooka” (gwarantowane rozszerzenie zakresu)
Co jeśli utknę i nie wiem jak coś zrobić?
Moja strategia:
1. Google (15 min) – „How to serialize LocalDateTime to JSON Java”
2. Stack Overflow (15 min) – czytam różne rozwiązania
3. ChatGPT (10 min) – pytam o konkretny problem
4. Discord/forum kursu (24h) – pytam instruktora
5. Następnego dnia świeży umysł– czasem sen rozwiązuje
Zasada: Max 1h szukania rozwiązania. Potem przerwa/pomoc.
Czy pokazać projekt w portfolio?
TAK! Nawet prosty projekt pokazuje:
- Umiesz skończyć, co zaczynasz
- Rozumiesz OOP i design patterns
- Piszesz czysty kod
- Rozwiązujesz problemy
Lepiej: 1 skończony prosty projekt niż 10 nie skończonych „ambitnych”.
Podsumowanie – mój pierwszy prawdziwy projekt
Therapy Manager v1.0:
- 47 klas
- 2847 linii kodu
- 55 godzin pracy
- 5 tygodni od pomysłu do finiszu
- Aplikacja która rozwiązuje mój realny problem
Co zyskałam:
- Umiejętność projektowania aplikacji
- Pewność siebie jako programistka
- Element portfolio (pokazuję na GitHubie)
- Praktyczne narzędzie (używam codziennie!)
Najważniejsza lekcja:
„Programowania nie uczy się przez czytanie poradników. Uczy się przez BUDOWANIE.”
Możesz przeczytać 100 tutoriali o Javie. Ale dopiero gdy zbudujesz projekt – rozumiesz jak to wszystko się łączy.
Pierwszy projekt w Java to przełom. Od „osoby która się uczy” do „osoby która buduje”.
I jeśli ja mogłam – z godzinę dziennie, z dziećmi w terapiach, między freelancingiem – to Ty też możesz.
Zbuduj coś. Zakończ to. Świętuj.
PS: Też budujesz swój pierwszy projekt? Utknąłeś gdzieś? Napisz w komentarzu – chętnie pomogę! A jeśli skończyłeś projekt – podziel się, co zbudowałeś? Ciekawa jestem!
Zostaw Komentarz