Skip to content

Commit 6beb513

Browse files
committed
refactor
1 parent 7793e17 commit 6beb513

File tree

148 files changed

+692
-9366
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

148 files changed

+692
-9366
lines changed

.github/workflows/labs.yml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ jobs:
3131
cd 0_intro/01_hello
3232
pytest -v --tb=short
3333
34-
lab-02-solid-srp:
35-
name: "Lab 02 - SOLID: SRP (10 pts)"
34+
lab-02-grasp-coupling:
35+
name: "Lab 02 - GRASP: Low Coupling (10 pts)"
3636
runs-on: ubuntu-latest
3737

3838
steps:
@@ -51,11 +51,11 @@ jobs:
5151
5252
- name: Run Lab 02 tests
5353
run: |
54-
cd 1_principles/01_solid/01_srp
54+
cd 1_principles/01_grasp/04_low_coupling
5555
pytest -v --tb=short
5656
57-
lab-03-grasp-expert:
58-
name: "Lab 03 - GRASP: Expert (10 pts)"
57+
lab-03-solid-ocp:
58+
name: "Lab 03 - SOLID: OCP (10 pts)"
5959
runs-on: ubuntu-latest
6060

6161
steps:
@@ -74,14 +74,14 @@ jobs:
7474
7575
- name: Run Lab 03 tests
7676
run: |
77-
cd 1_principles/02_grasp/01_information_expert
77+
cd 1_principles/02_solid/02_ocp
7878
pytest -v --tb=short
7979
8080
# Summary job - pokazuje ogólny status
8181
summary:
8282
name: "Summary"
8383
runs-on: ubuntu-latest
84-
needs: [lab-01-intro-hello, lab-02-solid-srp, lab-03-grasp-expert]
84+
needs: [lab-01-intro-hello, lab-02-grasp-coupling, lab-03-solid-ocp]
8585
if: always()
8686

8787
steps:
@@ -91,6 +91,6 @@ jobs:
9191
echo "Design Patterns Workshop - Test Summary"
9292
echo "============================================"
9393
echo "Lab 01 - Intro Calculator: ${{ needs.lab-01-intro-hello.result }}"
94-
echo "Lab 02 - SOLID SRP: ${{ needs.lab-02-solid-srp.result }}"
95-
echo "Lab 03 - GRASP Expert: ${{ needs.lab-03-grasp-expert.result }}"
94+
echo "Lab 02 - GRASP Low Coupling: ${{ needs.lab-02-grasp-coupling.result }}"
95+
echo "Lab 03 - SOLID OCP: ${{ needs.lab-03-solid-ocp.result }}"
9696
echo "============================================"

0_intro/01_hello/README.md

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,40 @@
1-
# 👋 Intro - Simple Calculator
1+
# 👋 Intro - Prosty Kalkulator
22

3-
**Difficulty**: very easy
4-
**Time**: 5 minutes
5-
**Focus**: Setup verification
3+
**Poziom**: bardzo łatwy
4+
**Cel**: Weryfikacja środowiska
65

76
## 🎯 Zadanie
87
Zaimplementuj dwie proste funkcje, żeby sprawdzić, że środowisko działa poprawnie.
98

109
## 📋 Wymagania
11-
- [ ] `add(2, 3)` zwraca `5`
12-
- [ ] `add(10, 5)` zwraca `15`
13-
- [ ] `multiply(2, 3)` zwraca `6`
14-
- [ ] `multiply(10, 5)` zwraca `50`
15-
- [ ] Funkcje działają z liczbami ujemnymi i zerem
10+
- [ ] Przechodzą doctesty
11+
- [ ] Przechodzą testy jednostkowe (pytest)
12+
- [ ] Funkcje działają z liczbami dodatnimi, ujemnymi i zerem
1613

1714
## 🚀 Jak zacząć
1815
1. Otwórz `starter.py`
19-
2. Uruchom doctests: `python -m doctest starter.py -v`
16+
2. Uruchom testy (powinny failować):
17+
- Doctests: `python -m doctest starter.py -v`
18+
- Pytest: `pytest` (lub `pytest -v` dla bardziej szczegółowego outputu)
2019
3. Zaimplementuj funkcje `add()` i `multiply()`
21-
4. Uruchom testy: `python -m pytest test_hello.py -v`
22-
5. Commit gdy wszystkie testy przechodzą ✅
20+
4. Uruchom testy ponownie (teraz powinny przejść)
21+
5. Gdy wszystkie testy przechodzą:
22+
```bash
23+
git add .
24+
git commit -m "Complete Lab 01 - Calculator"
25+
git push
26+
```
27+
6. Sprawdź wynik w GitHub:
28+
- Wejdź w zakładkę **Actions** w swoim repo
29+
- Znajdź job "Lab 01 - Intro: Calculator"
30+
- ✅ Zielony = zadanie zaliczone!
2331

2432
## 💡 Podpowiedź
25-
- Sprawdź doctests w `starter.py` - pokazują expected behavior
33+
- Sprawdź doctests w `starter.py` - pokazują oczekiwane zachowanie
2634
- `add(a, b)` powinno zwrócić sumę: `a + b`
2735
- `multiply(a, b)` powinno zwrócić iloczyn: `a * b`
2836

29-
## ✅ Success criteria
30-
Gdy uruchomisz:
31-
```bash
32-
python -m doctest starter.py -v
33-
python -m pytest test_hello.py -v
34-
```
37+
## ✅ Kryteria sukcesu
38+
Wszystkie testy przechodzą (zielone ✅).
3539

36-
Wszystkie testy powinny być zielone ✅
37-
38-
Jeśli wszystkie testy przeszły, Twoje środowisko działa poprawnie.
39-
🎉 Gratulacje!
40+
Jeśli tak, środowisko działa poprawnie. 🎉
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# 🔗 GRASP Low Coupling - System Gry
2+
3+
**Poziom**: łatwy
4+
**Cel**: GRASP Low Coupling
5+
6+
## 🎯 Zadanie
7+
Zaimplementuj `Game` i `ScoreService` (pośrednika), aby zredukować sprzężenie między `Game` a `Database`.
8+
9+
## 📋 Wymagania
10+
- [ ] Przechodzą doctesty
11+
- [ ] Przechodzą testy jednostkowe (pytest)
12+
- [ ] `Game` używa `ScoreService` jako pośrednika (nie zna `Database`)
13+
14+
## 🚀 Jak zacząć
15+
1. Otwórz `starter.py`
16+
2. Uruchom testy (powinny failować):
17+
- Doctests: `python -m doctest starter.py -v`
18+
- Pytest: `pytest` (lub `pytest -v` dla bardziej szczegółowego outputu)
19+
3. Zaimplementuj klasę `ScoreService`
20+
4. Zaimplementuj klasę `Game` z dependency injection
21+
5. Uruchom testy ponownie (teraz powinny przejść)
22+
6. Gdy wszystkie testy przechodzą:
23+
```bash
24+
git add .
25+
git commit -m "Complete Lab XX - Low Coupling"
26+
git push
27+
```
28+
7. Sprawdź wynik w GitHub Actions
29+
30+
## 💡 GRASP Low Coupling w pigułce
31+
32+
**Minimalizuj zależności między klasami**
33+
34+
**Źle** (silne sprzężenie):
35+
```python
36+
class Game:
37+
def finish_game(self, player, score):
38+
db = Database() # Bezpośrednia zależność ❌
39+
db.connect()
40+
db.save(player, score)
41+
# Game zna szczegóły Database - silne sprzężenie
42+
```
43+
44+
**Dobrze** (luźne sprzężenie):
45+
```python
46+
class Game:
47+
def __init__(self, score_service): # Pośrednik ✅
48+
self.score_service = score_service
49+
50+
def finish_game(self, player, score):
51+
self.score_service.save_score(player, score)
52+
# Game nie zna Database - luźne sprzężenie
53+
54+
# ScoreService izoluje Game od Database
55+
```
56+
57+
**Korzyść**: Zmiana Database nie wpływa na Game. Łatwe testowanie (mock ScoreService).
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
"""
2+
GRASP Low Coupling - Game System
3+
4+
>>> # Test ScoreService
5+
>>> service = ScoreService()
6+
>>> service.save_score("player1", 100)
7+
'Saved score 100 for player1'
8+
9+
>>> # Test Game with ScoreService (low coupling)
10+
>>> game = Game(service)
11+
>>> game.finish_game("Alice", 150)
12+
'Game finished. Saved score 150 for Alice'
13+
"""
14+
15+
16+
class Database:
17+
"""Konkretna implementacja bazy danych"""
18+
19+
def connect(self) -> str:
20+
return "Connected to database"
21+
22+
def save(self, player: str, score: int) -> str:
23+
return f"Saved score {score} for {player}"
24+
25+
26+
# TODO: Zaimplementuj ScoreService
27+
# Klasa pośrednicząca między Game a bazą danych (redukuje sprzężenie)
28+
# Metoda save_score(player, score) zwraca: "Saved score {score} for {player}"
29+
30+
class ScoreService:
31+
pass
32+
33+
34+
# TODO: Zaimplementuj Game
35+
# Przyjmuje score_service: ScoreService w konstruktorze (dependency injection)
36+
# Metoda finish_game(player, score):
37+
# - Wywołuje score_service.save_score(player, score)
38+
# - Zwraca "Game finished. {wynik z save_score}"
39+
#
40+
# Low Coupling: Game nie zna Database, tylko ScoreService (pośrednik)
41+
42+
class Game:
43+
pass
44+
45+
46+
# GRASP Low Coupling:
47+
# Minimalizuj zależności między klasami
48+
#
49+
# Silne sprzężenie ❌:
50+
# Game → Database (bezpośrednia zależność)
51+
#
52+
# Luźne sprzężenie ✅:
53+
# Game → ScoreService → Database (pośrednik)
54+
#
55+
# Korzyść: Zmiana Database nie wpływa na Game
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
"""
2+
❌ VIOLATION of GRASP Low Coupling
3+
4+
Problem: Game bezpośrednio zależy od Database
5+
- Silne sprzężenie - Game "wie" o szczegółach bazy danych
6+
- Zmiana Database wymaga modyfikacji Game
7+
- Trudne testowanie - nie można łatwo zamockować Database
8+
- Naruszenie Low Coupling: zbyt wiele zależności między klasami
9+
"""
10+
11+
12+
class Database:
13+
"""
14+
Konkretna implementacja bazy danych
15+
16+
UWAGA: Użyj tej klasy w ScoreService, NIE w Game!
17+
Game powinien znać tylko ScoreService (pośrednika)
18+
"""
19+
20+
def connect(self) -> str:
21+
return "Connected to database"
22+
23+
def save(self, player: str, score: int) -> str:
24+
return f"Saved score {score} for {player}"
25+
26+
27+
class Game:
28+
"""
29+
❌ PROBLEM: Bezpośrednia zależność od Database
30+
31+
Konsekwencje:
32+
1. Silne sprzężenie - Game musi znać Database
33+
2. Trudne testowanie - wymaga prawdziwej bazy lub użycia patcha
34+
3. Zmiana Database = zmiana Game
35+
4. Game odpowiada za logikę gry ORAZ komunikację z bazą
36+
"""
37+
38+
def finish_game(self, player: str, score: int) -> str:
39+
"""
40+
❌ Tworzy Database bezpośrednio w metodzie
41+
"""
42+
# ❌ PROBLEM: Bezpośrednie tworzenie Database
43+
# Game "wie" o Database - silne sprzężenie
44+
db = Database()
45+
46+
# ❌ PROBLEM: Game zna szczegóły implementacji Database
47+
# Musi wiedzieć że trzeba najpierw connect(), potem save()
48+
result = db.connect()
49+
result += "\n" + db.save(player, score)
50+
51+
return f"Game finished.\n{result}"
52+
53+
54+
# ❌ Przykład użycia - działa, ale narusza Low Coupling
55+
if __name__ == "__main__":
56+
game = Game()
57+
print(game.finish_game("Alice", 150))
58+
59+
# ❌ Chcę przetestować Game bez prawdziwej bazy?
60+
# Nie mogę - Game tworzy Database bezpośrednio w finish_game() (ew. patch)
61+
#
62+
# ❌ Chcę zmienić Database na inną implementację?
63+
# Muszę EDYTOWAĆ Game.finish_game()
64+
#
65+
# ❌ Chcę dodać cache między Game a Database?
66+
# Muszę EDYTOWAĆ Game - nie ma miejsca na pośrednika
67+
#
68+
# To naruszenie Low Coupling!
69+
70+
71+
"""
72+
Dlaczego to jest ZŁE?
73+
74+
1. ❌ Silne sprzężenie
75+
- Game bezpośrednio zależy od Database
76+
- Game musi znać szczegóły Database (connect, save)
77+
- Trudno zmienić implementację
78+
79+
2. ❌ Trudne testowanie
80+
- Nie można wstrzyknąć mock Database, trzeba patchować
81+
- Trudno testować Game w izolacji
82+
83+
3. ❌ Brak elastyczności
84+
- Nie można dodać pośrednika (cache, logger)
85+
- Zmiana Database wymaga zmiany Game
86+
- Naruszenie Open/Closed
87+
88+
4. ❌ Naruszenie Single Responsibility
89+
- Game odpowiada za logikę gry
90+
- Game odpowiada za komunikację z bazą
91+
- Dwie odpowiedzialności w jednej klasie
92+
93+
5. ❌ Wysokie sprzężenie = niska "współużywalność"
94+
- Game nie może działać bez Database
95+
- Nie można użyć Game z innym storage (file, API)
96+
97+
Jak to naprawić?
98+
1. Stwórz ScoreService jako pośrednika
99+
2. Game przyjmuje ScoreService w konstruktorze (dependency injection)
100+
3. ScoreService izoluje Game od Database
101+
4. Game nie zna szczegółów Database - tylko wywołuje score_service.save_score()
102+
"""

0 commit comments

Comments
 (0)