Używamy cookies, żeby zwiększyć Twoje doświadczenia na stronie
CodeWorlds

Najlepsze praktyki

Tym razem Dr. Ian Malcolm wraz z całym zespołem Parku Jurajskiego przygotowali dla Ciebie kluczowy briefing. Po kilku incydentach w parku, w tym słynnej awarii systemu i ucieczce dinozaurów, zespół opracował zestaw najlepszych praktyk programistycznych, które mogłyby zapobiec podobnym katastrofom w przyszłości.

Zasady, które mogłyby uratować Park Jurajski

1. Waliduj wszystkie dane wejściowe

Problem w parku: System nie sprawdzał poprawnie danych o temperaturze inkubatorów jaj dinozaurów, co doprowadziło do niekontrolowanego rozmnażania się welociraptorów.

Rozwiązanie:

1// Źle:
2function ustawTemperaturęInkubatora(temperatura) {
3  inkubator.temperatura = temperatura;
4  // Co jeśli temperatura będzie zbyt wysoka? Lub to będzie string zamiast liczby?
5}
6
7// Dobrze:
8function ustawTemperaturęInkubatora(temperatura) {
9  // Sprawdzamy czy temperatura jest liczbą
10  if (typeof temperatura !== 'number') {
11    throw new Error('Temperatura musi być liczbą');
12  }
13
14  // Sprawdzamy czy temperatura mieści się w bezpiecznym zakresie
15  if (temperatura < 20 || temperatura > 40) {
16    throw new Error('Temperatura poza bezpiecznym zakresem (20-40°C)');
17  }
18
19  inkubator.temperatura = temperatura;
20}

2. Używaj testów automatycznych

Problem w parku: Nikt nie przetestował systemu ogrodzenia elektrycznego w warunkach ekstremalnych, takich jak tropikalna burza.

Rozwiązanie:

1// Zestaw testów dla systemu ogrodzenia
2describe('System ogrodzenia', () => {
3  test('powinien działać przy normalnym zasilaniu', () => {
4    const ogrodzenie = new SystemOgrodzenia();
5    ogrodzenie.włącz();
6    expect(ogrodzenie.czyAktywne()).toBe(true);
7  });
8
9  test('powinien przełączyć się na zasilanie awaryjne podczas burzy', () => {
10    const ogrodzenie = new SystemOgrodzenia();
11    ogrodzenie.włącz();
12    ogrodzenie.symulujPrzerwęWDostawieEnergii();
13    expect(ogrodzenie.czyAktywne()).toBe(true);
14    expect(ogrodzenie.źródłoZasilania).toBe('awaryjne');
15  });
16
17  test('powinien wysłać alert gdy baterie awaryjne są poniżej 20%', () => {
18    const ogrodzenie = new SystemOgrodzenia();
19    const alertMock = jest.fn();
20    ogrodzenie.onNiskiPoziomBaterii = alertMock;
21
22    ogrodzenie.ustawPoziomBaterii(15);
23
24    expect(alertMock).toHaveBeenCalled();
25  });
26});

3. Stosuj zasadę pojedynczej odpowiedzialności

Problem w parku: Jeden system sterował zarówno drzwiami, jak i ogrodzeniami, kamerami oraz systemem bezpieczeństwa. Awaria jednego komponentu doprowadziła do kaskadowej awarii całego systemu.

Rozwiązanie:

1// Źle:
2class SystemParku {
3  kontrolujDrzwi() { /* ... */ }
4  zarządzajOgrodzeniem() { /* ... */ }
5  monitorujKamery() { /* ... */ }
6  sterujKlimatyzacją() { /* ... */ }
7  // Ten obiekt robi zbyt wiele!
8}
9
10// Dobrze:
11class SystemDrzwi {
12  otwórz(id) { /* ... */ }
13  zamknij(id) { /* ... */ }
14  sprawdźStan(id) { /* ... */ }
15}
16
17class SystemOgrodzenia {
18  włącz() { /* ... */ }
19  wyłącz() { /* ... */ }
20  sprawdźNapięcie() { /* ... */ }
21}
22
23class SystemMonitoringu {
24  włączKamerę(id) { /* ... */ }
25  wyłączKamerę(id) { /* ... */ }
26  nagrywaj(id) { /* ... */ }
27}
28
29class CentralnySterownik {
30  constructor(systemDrzwi, systemOgrodzenia, systemMonitoringu) {
31    this.systemDrzwi = systemDrzwi;
32    this.systemOgrodzenia = systemOgrodzenia;
33    this.systemMonitoringu = systemMonitoringu;
34  }
35
36  uruchomProcedurębezpieczeństwa() {
37    // Teraz koordynuje niezależne systemy
38    this.systemDrzwi.zamknij('wszystkie');
39    this.systemOgrodzenia.włącz();
40    this.systemMonitoringu.nagrywaj('wszystkie');
41  }
42}

4. Obsługuj błędy i wyjątki

Problem w parku: System transportu jaj nie posiadał obsługi błędów, co doprowadziło do utraty cennego materiału genetycznego, gdy jeden z czujników przestał działać.

Rozwiązanie:

1// Źle:
2function przenieśJajo(idJaja, docelowaPozycja) {
3  const jajo = bazaDanych.pobierzJajo(idJaja);
4  ramięRobotyczne.przenieś(jajo, docelowaPozycja);
5  bazaDanych.aktualizujPozycję(idJaja, docelowaPozycja);
6  // Co jeśli którakolwiek z tych operacji się nie powiedzie?
7}
8
9// Dobrze:
10async function przenieśJajo(idJaja, docelowaPozycja) {
11  try {
12    // Pobieramy jajo z bazy
13    const jajo = await bazaDanych.pobierzJajo(idJaja);
14    if (!jajo) {
15      throw new Error(`Jajo o ID ${idJaja} nie zostało znalezione`);
16    }
17
18    // Przenosimy jajo za pomocą ramienia robotycznego
19    try {
20      await ramięRobotyczne.przenieś(jajo, docelowaPozycja);
21    } catch (błąd) {
22      console.error('Błąd podczas przenoszenia jaja:', błąd);
23      wyslijAlert('Błąd ramienia robotycznego', błąd.message);
24      return false;
25    }
26
27    // Aktualizujemy pozycję w bazie danych
28    await bazaDanych.aktualizujPozycję(idJaja, docelowaPozycja);
29
30    // Logujemy udaną operację
31    logOperacji.dodaj(`Jajo ${idJaja} przeniesione do ${docelowaPozycja}`);
32
33    return true;
34  } catch (błąd) {
35    console.error('Krytyczny błąd podczas przenoszenia jaja:', błąd);
36    wyslijAlert('Krytyczny błąd', błąd.message);
37    uruchomProcedurębezpieczeństwa();
38    return false;
39  }
40}

5. Dokumentuj swój kod

Problem w parku: Po odejściu głównego inżyniera, nikt nie wiedział dokładnie jak działa system kontroli dostępu.

Rozwiązanie:

1/**
2 * Weryfikuje poziom dostępu pracownika do stref parku.
3 *
4 * @param {Object} pracownik - Obiekt zawierający dane pracownika
5 * @param {string} pracownik.id - Unikalny identyfikator pracownika
6 * @param {string} pracownik.imię - Imię pracownika
7 * @param {string} pracownik.nazwisko - Nazwisko pracownika
8 * @param {number} pracownik.poziomDostępu - Poziom dostępu pracownika (1-5)
9 * @param {string} strefa - Identyfikator strefy, do której pracownik próbuje uzyskać dostęp
10 * @returns {boolean} - Zwraca true, jeśli pracownik ma dostęp do strefy, false w przeciwnym razie
11 *
12 * @example
13 * // Sprawdź czy Dr. Wu ma dostęp do laboratorium
14 * const drWu = { id: '001', imię: 'Henry', nazwisko: 'Wu', poziomDostępu: 5 };
15 * const dostęp = sprawdźDostęp(drWu, 'laboratorium');
16 * console.log(dostęp); // true
17 */
18function sprawdźDostęp(pracownik, strefa) {
19  // Mapa wymaganych poziomów dostępu dla różnych stref
20  const wymaganyPoziom = {
21    'publiczna': 1,
22    'administracja': 2,
23    'zwierzęta roślinożerne': 3,
24    'drapieżniki': 4,
25    'laboratorium': 5
26  };
27
28  // Sprawdź czy strefa istnieje
29  if (!wymaganyPoziom.hasOwnProperty(strefa)) {
30    console.warn(`Nieznana strefa: ${strefa}`);
31    return false;
32  }
33
34  // Porównaj poziom dostępu pracownika z wymaganym dla strefy
35  return pracownik.poziomDostępu >= wymaganyPoziom[strefa];
36}

6. Unikaj globalnego stanu

Problem w parku: System kontroli klimatu używał globalnych zmiennych do przechowywania ustawień, co pozwoliło błędowi w module sterowania wentylacją wpłynąć na cały system klimatyzacji.

Rozwiązanie:

1// Źle:
2let globalnaTemperatura = 22;
3let globalnaWilgotność = 70;
4
5function ustawTemperaturęWDżungli() {
6  // Modyfikuje zmienne globalne
7  globalnaTemperatura = 28;
8  globalnaWilgotność = 90;
9}
10
11function ustawTemperaturęWLaboratorium() {
12  // Również modyfikuje te same zmienne globalne!
13  globalnaTemperatura = 20;
14  globalnaWilgotność = 50;
15}
16
17// Co się stanie, jeśli obie funkcje zostaną wywołane blisko siebie w czasie?
18
19// Dobrze:
20class KontrolerKlimatu {
21  constructor() {
22    this.strefy = new Map();
23  }
24
25  ustawParametryStefy(idStrefy, temperatura, wilgotność) {
26    this.strefy.set(idStrefy, { temperatura, wilgotność });
27  }
28
29  pobierzParametryStefy(idStrefy) {
30    return this.strefy.get(idStrefy);
31  }
32}
33
34const kontrolerKlimatu = new KontrolerKlimatu();
35
36kontrolerKlimatu.ustawParametryStefy('dżungla', 28, 90);
37kontrolerKlimatu.ustawParametryStefy('laboratorium', 20, 50);
38
39// Teraz każda strefa ma własne niezależne ustawienia

7. Stosuj DRY (Don't Repeat Yourself)

Problem w parku: Kod do sprawdzania stanu zagrożenia był powielony w kilku systemach, więc poprawka błędu w jednym systemie nie została wprowadzona w pozostałych.

Rozwiązanie:

1// Źle:
2function sprawdźZagrożenieWSystemieDrzwi() {
3  if (czujniki.ruch > 10 && czujniki.dźwięk > 80 && !jestDzień()) {
4    ogłośAlarm('Podejrzana aktywność przy drzwiach!');
5  }
6}
7
8function sprawdźZagrożenieWSystemieOgrodzenia() {
9  // Ten sam logika jest powtórzona!
10  if (czujniki.ruch > 10 && czujniki.dźwięk > 80 && !jestDzień()) {
11    ogłośAlarm('Podejrzana aktywność przy ogrodzeniu!');
12  }
13}
14
15// Dobrze:
16function wykryjPodejrzanąAktywność() {
17  return czujniki.ruch > 10 && czujniki.dźwięk > 80 && !jestDzień();
18}
19
20function sprawdźZagrożenieWSystemieDrzwi() {
21  if (wykryjPodejrzanąAktywność()) {
22    ogłośAlarm('Podejrzana aktywność przy drzwiach!');
23  }
24}
25
26function sprawdźZagrożenieWSystemieOgrodzenia() {
27  if (wykryjPodejrzanąAktywność()) {
28    ogłośAlarm('Podejrzana aktywność przy ogrodzeniu!');
29  }
30}

8. Pisz kod dla ludzi, nie dla komputerów

Problem w parku: Kod genetyczny napisany przez Dr. Wu był tak zagmatwany, że nikt inny nie rozumiał jak dokładnie tworzono hybrydowe dinozaury.

Rozwiązanie:

1// Źle:
2function ms(d,g,s) {
3  const r = [];
4  for(let i=0;i<d.length;i++) {
5    if(d[i].g === g && d[i].t > s) {
6      r.push(d[i]);
7    }
8  }
9  return r;
10}
11
12// Dobrze:
13/**
14 * Filtruje dinozaury według gatunku i minimalnego poziomu siły
15 */
16function filtrujDinozauryPoGatunkuISile(dinozaury, gatunek, minimalnaSila) {
17  const wyfiltrowane = [];
18
19  for (let i = 0; i < dinozaury.length; i++) {
20    const dinozaur = dinozaury[i];
21
22    if (dinozaur.gatunek === gatunek && dinozaur.siła > minimalnaSila) {
23      wyfiltrowane.push(dinozaur);
24    }
25  }
26
27  return wyfiltrowane;
28}
29
30// Lub jeszcze lepiej, używając nowoczesnego JavaScript:
31function filtrujDinozauryPoGatunkuISile(dinozaury, gatunek, minimalnaSila) {
32  return dinozaury.filter(dinozaur =>
33    dinozaur.gatunek === gatunek && dinozaur.siła > minimalnaSila
34  );
35}

9. Używaj kontroli wersji

Problem w parku: Zespół IT nie używał systemu kontroli wersji, więc po wprowadzeniu nowej funkcjonalności, która okazała się zawierać błędy, nie można było łatwo przywrócić poprzedniej działającej wersji.

Rozwiązanie:

1# Inicjalizacja repozytorium Git
2git init
3
4# Dodanie plików do repozytorium
5git add .
6
7# Pierwszy commit
8git commit -m "Początkowa wersja systemu Parku Jurajskiego"
9
10# Tworzenie nowej gałęzi na potrzeby rozwoju nowej funkcjonalności
11git checkout -b nowy-system-karmienia
12
13# Praca nad funkcjonalnością...
14
15# Zapisanie zmian
16git add zmodyfikowane-pliki
17git commit -m "Dodano automatyczny system karmienia dla drapieżników"
18
19# Łączenie zmian z główną gałęzią po testach
20git checkout main
21git merge nowy-system-karmienia
22
23# W przypadku problemów, można szybko wrócić do poprzedniej wersji
24git revert HEAD

10. Stosuj przeglądowanie kodu (code review)

Problem w parku: Dennis Nedry wprowadził tylne drzwi do systemu bezpieczeństwa, których nikt nie zauważył, ponieważ nie było procesu przeglądania kodu.

Podejście w zespole:

  1. Każda zmiana musi być przeglądnięta przez co najmniej jednego innego programistę
  2. Automatyczne testy muszą przejść przed scaleniem kodu
  3. Stosowanie listy kontrolnej podczas przeglądania:
    • Czy kod jest zgodny ze standardami?
    • Czy potencjalne problemy bezpieczeństwa zostały zaadresowane?
    • Czy dokumentacja została zaktualizowana?
    • Czy testy pokrywają nowy kod?

Koszt nieprzestrzegania najlepszych praktyk

Jak już wiemy z historii Parku Jurajskiego, nieprzestrzeganie najlepszych praktyk programistycznych może prowadzić do katastrofalnych konsekwencji:

  1. Utrata danych: Bezcenny materiał genetyczny dinozaurów utracony z powodu błędów w systemie
  2. Zagrożenie bezpieczeństwa: Awarie systemu prowadzące do ucieczki niebezpiecznych stworzeń
  3. Przerwy w działaniu: Zamknięcie parku z powodu problemów technicznych
  4. Trudności w rozwoju: Niemożność szybkiego wprowadzania nowych funkcji
  5. Problemy z utrzymaniem: Trudny do zrozumienia i naprawy kod

Ćwiczenie

Wyobraź sobie, że jesteś głównym programistą w Parku Jurajskim. Zidentyfikuj wszystkie potencjalne problemy w poniższym kodzie i przepisz go zgodnie z najlepszymi praktykami:

1// System monitorowania dinozaurów w Parku Jurajskim
2var dinos = [];
3var alarmy = 0;
4
5function dodaj(name, type, area, dangerLvl) {
6  dinos.push({n: name, t: type, a: area, d: dangerLvl, h: 100});
7  console.log('dodano: ' + name);
8}
9
10function check() {
11  for (var i=0; i<dinos.length; i++) {
12    if (dinos[i].h < 50) {
13      console.log('UWAGA! Dinozaur ' + dinos[i].n + ' ma niski poziom zdrowia!');
14      alarmy = alarmy + 1;
15    }
16
17    if (dinos[i].a != dinos[i].lockArea && dinos[i].d > 3) {
18      console.log('NIEBEZPIECZEŃSTWO! Drapieżnik poza strefą!');
19      alarmy = alarmy + 1;
20    }
21  }
22
23  if (alarmy > 0) alert('Mamy problemy...');
24}
25
26// Przykład użycia
27dodaj('Rex', 'T-Rex', 'B5', 5);
28dodaj('Tri', 'Triceratops', 'A2', 2);
29dinos[0].h = 30;
30dinos[0].a = 'X3'; // Poza przypisaną strefą!
31check();

Pamiętaj, w świecie programowania, tak jak w Parku Jurajskim - życie zawsze znajdzie sposób... na ujawnienie nieprzemyślanych rozwiązań! Dlatego stosuj najlepsze praktyki, aby twój kod był bezpieczny, utrzymywalny i efektywny.

Przejdź do CodeWorlds