Największe błędy w programowaniu, których AI nie popełni – ale Ty możesz

Sztuczna inteligencja może wiele nauczyć nas o dobrych praktykach programistycznych. Często AI działa bezbłędnie tam, gdzie my ludzie możemy się pomylić. W tym artykule znajdziesz przykłady typowych błędów oraz prompty do chata GPT, które pomogą Ci udoskonalić kod i podnieść jakość projektu.

Testowanie kodu – niedoceniany fundament jakości

Testowanie kodu często odkładane są na później, ale pełne testy to inwestycja, która może uchronić Twój projekt przed nieprzewidzianymi błędami.

Ubezpiecz się – stwórz testy na każdą sytuację, nawet te nieoczywiste.

Przykładowy kod wejściowy (C#):

public decimal CalculateTotal(List<Item> cartItems, decimal discount)
{
    decimal total = 0;

    foreach (var item in cartItems)
    {
        total += item.Price * item.Quantity;
    }

    total -= total * (discount / 100);

    return total;
}

🤖 Prompt

Napisz zestaw testów jednostkowych w C# dla funkcji CalculateTotal(List<Item> cartItems, decimal discount). Przetestuj przypadki, takie jak pusty koszyk, zerowy oraz ujemny rabat, i sytuację, gdy rabat przekracza 100%. Dodaj przypadki krańcowe dla wartości Price i Quantity.

Odpowiedź ChatGPT 4o: Przykład zestawu testów jednostkowych dla funkcji CalculateTotal, które pomagają wykryć błędy i poprawić jakość kodu.

Odpowiedź ChatGPT 4o: Przykład zestawu testów jednostkowych dla funkcji CalculateTotal, które pomagają wykryć błędy i poprawić jakość kodu.

Czytelność kodu – ułatwia współpracę i rozumienie logiki

Czytelność kodu jest fundamentem pracy zespołowej i skutecznego zarządzania projektem.

Opisowe nazwy zmiennych, klarowne komentarze - to brak nieporozumień i łatwiejsze utrzymanie w dłuższej perspektywie.

Pisząc kod, który jest przejrzysty i zrozumiały, zmniejszasz ryzyko błędów oraz przyspieszasz wdrażanie nowych członków zespołu.

To przełoży się się na wyższą jakość i stabilność projektu.

Przykładowy kod wejściowy (JavaScript):

function calcTotal(items, disc) {
    let tot = 0;

    items.forEach(item => {
        tot += item.price * item.qty;
    });

    tot -= tot * (disc / 100);

    return tot;
}

🤖 Prompt

Zrefaktoryzuj funkcję calcTotal(items, disc) w JavaScript, aby poprawić czytelność. Użyj bardziej opisowych nazw zmiennych, np. items na cartItems, tot na totalAmount, disc na discount. Dodaj komentarze opisujące kroki obliczeń.

Odpowiedź ChatGPT 4o: Refaktoryzacja funkcji calcTotal, która dzięki opisowym nazwom i komentarzom zwiększa przejrzystość kodu.

Odpowiedź ChatGPT 4o: Refaktoryzacja funkcji calcTotal, która dzięki opisowym nazwom i komentarzom zwiększa przejrzystość kodu.

Optymalizacja kodu – szybsze działanie dzięki odpowiednim technologiom

Optymalizacja kodu zapewni skalowalność i wysoką wydajność Twojej aplikacji, szczególnie jeśli pracujesz z dużymi zbiorami danych.

Efektywne wykorzystanie struktur danych oraz algorytmów o niskiej złożoności obliczeniowej pozwoli Ci zredukować czas przetwarzania i zmniejszyć zużycie zasobów systemowych. 

Przykładowy kod wejściowy (JavaScript):

function processOrders(orders) {
    let results = [];

    for (let i = 0; i < orders.length; i++) {
        results.push(fetchOrderDetails(orders[i]));
    }

    return Promise.all(results);
}

🤖 Prompt

Zoptymalizuj funkcję processOrders(orders) w JavaScript, aby efektywnie pobierała szczegóły zamówień asynchronicznie, przy użyciu Promise.all() oraz async/await. Użyj for...of z await dla przyspieszenia przetwarzania dużych zestawów zamówień.

Odpowiedź ChatGPT 4o: Zoptymalizowana funkcja processOrders do asynchronicznego pobierania danych, co zwiększa wydajność przy dużych zbiorach zamówień.

Odpowiedź ChatGPT 4o: Zoptymalizowana funkcja processOrders do asynchronicznego pobierania danych, co zwiększa wydajność przy dużych zbiorach zamówień.

Unikaj powielania kodu – refaktoryzacja zwiększa czytelność i utrzymywalność

Duplikacja kodu prowadzi do chaosu, szczególnie w dużych projektach.

Powtarzające się fragmenty kodu zwiększają ryzyko błędów, ponieważ każda zmiana wymaga edycji wielu miejsc. 

Przykładowy kod wejściowy (C#):

public decimal CalculateTax(decimal price)
{
    return price * 0.2m;
}

public decimal CalculateDiscount(decimal price)
{
    return price * 0.1m;
}

public decimal CalculateTotal(decimal price)
{
    decimal tax = price * 0.2m;
    decimal discount = price * 0.1m;

    return price + tax - discount;
}

🤖 Prompt

Zrefaktoryzuj kod w C# tak, aby powtarzające się obliczenia podatku i rabatu były wyodrębnione do jednej metody CalculateAdjustment(decimal price, decimal rate). Wykorzystaj ją w CalculateTax i CalculateDiscount.

Odpowiedź ChatGPT 4o: Refaktoryzacja obliczeń podatku i rabatu, by uniknąć duplikacji kodu i zwiększyć jego czytelność.

Odpowiedź ChatGPT 4o: Refaktoryzacja obliczeń podatku i rabatu, by uniknąć duplikacji kodu i zwiększyć jego czytelność.

Zarządzanie zależnościami – ogranicz liczbę bibliotek i zadbaj o kompatybilność

Zewnętrzne biblioteki bywają bardzo przydatne, ale gdy używamy ich rozsądnie.

Musimy pamiętać o kaskadach zależności, problemach z aktualizacjami czy konfliktami wersji.

Czasem lepiej wykorzystać wbudowane funkcje.

Przykładowy kod wejściowy (JavaScript):

const _ = require('lodash');

function getUniqueItems(items) {
    return _.uniqBy(items, 'id');
}

🤖 Prompt

Przepisz funkcję getUniqueItems(items) w JavaScript, aby uniknąć zależności od lodash. Wykorzystaj natywne metody JavaScript do zwracania unikalnych elementów w oparciu o id.

Odpowiedź ChatGPT 4o: Przepisana funkcja getUniqueItems bez użycia zewnętrznej biblioteki lodash, co zwiększa niezależność kodu.

Odpowiedź ChatGPT 4o: Przepisana funkcja getUniqueItems bez użycia zewnętrznej biblioteki lodash, co zwiększa niezależność kodu.

Trzymaj się standardów – ułatwisz współpracę i poprawia jakość projektu

Przestrzeganie standardów kodowania jest ważne dla utrzymania spójności i czytelności kodu.

Ujednolicone konwencje, obejmujące formatowanie, wcięcia czy nazewnictwo, minimalizują ryzyko błędów oraz przyspieszają proces przeglądów kodu. 

Przykładowy kod wejściowy (JavaScript):

let price=100; let tax=0.2;let totalPrice=price+price*tax;

console.log(totalPrice);

🤖 Prompt

Skonfiguruj ESLint dla projektu w JavaScript, aby wymusić przestrzeganie standardów kodowania, takich jak spacje wokół operatorów i jednolite formatowanie. Przepisz kod, aby był zgodny z tymi zasadami.

Odpowiedź ChatGPT 4o: Kod dostosowany do standardów ESLint w celu zwiększenia spójności i poprawienia czytelności projektu.

Odpowiedź ChatGPT 4o: Kod dostosowany do standardów ESLint w celu zwiększenia spójności i poprawienia czytelności projektu.

Dokumentacja – kluczowy element ułatwiający pracę zespołową

Dokumentacja jest nieoceniona dla zespołów pracujących nad złożonymi projektami.

Szczególnie tych o dużej skali.

Dobra dokumentacja redukuje potrzebę bezpośrednich konsultacji, wspiera onboarding nowych członków zespołu oraz ułatwia utrzymanie i rozbudowę projektu w długim terminie. 

Przykładowy kod wejściowy (C#):

public decimal CalculateDiscount(decimal price, decimal discountRate)
{
    return price - (price * discountRate);
}

🤖 Prompt

Napisz komentarz dokumentacyjny dla funkcji CalculateDiscount(decimal price, decimal discountRate) w C#. Opisz parametry, zwracaną wartość oraz potencjalne wyjątki.

Odpowiedź ChatGPT 4o: Komentarz dokumentacyjny opisujący funkcję CalculateDiscount, aby zwiększyć jej zrozumiałość i ułatwić pracę zespołową.

Odpowiedź ChatGPT 4o: Komentarz dokumentacyjny opisujący funkcję CalculateDiscount, aby zwiększyć jej zrozumiałość i ułatwić pracę zespołową.

Zabezpieczenie przed błędami – program defensywny to program bezpieczny

Błędy związane z niewłaściwymi danymi wejściowymi mogą być trudne do wykrycia.

Program defensywny zakłada, że zawsze może pojawić się nieoczekiwany scenariusz.

Więcej o defensywnym programowaniu pisałem tutaj: Explore the Top 20 Defensive Programming Principles in .NET.

Przykładowy kod wejściowy (C#):

public int Divide(int numerator, int denominator)
{
    return numerator / denominator;
}

🤖 Prompt

Zmodyfikuj funkcję Divide(int numerator, int denominator) w C#, aby obsługiwała wyjątki i przypadki, gdy denominator jest zerem. Dodaj wyświetlanie komunikatu o błędzie.

Odpowiedź ChatGPT 4o: Funkcja Divide z obsługą błędów dzielenia przez zero, co zwiększa stabilność aplikacji.

Odpowiedź ChatGPT 4o: Funkcja Divide z obsługą błędów dzielenia przez zero, co zwiększa stabilność aplikacji.

Sprawdzanie poprawności danych – dbaj o jakość danych na wejściu

Weryfikacja poprawności danych wejściowych to klucz do zapewnienia jakości i stabilności aplikacji. Niewłaściwe lub niekompletne dane mogą prowadzić do błędów, które są trudne do wykrycia i naprawy. Szczególnie w późniejszych etapach przetwarzania. 

Walidacja danych na etapie wejścia umożliwia szybkie wykrycie nieprawidłowości, redukuje ryzyko wystąpienia błędów oraz podnosi bezpieczeństwo aplikacji.

Przykładowy kod wejściowy (JavaScript):

function addUserToList(userList, user) {
    userList.push(user);
}

🤖 Prompt

Rozbuduj funkcję addUserToList(userList, user) w JavaScript, aby walidowała obiekt user, sprawdzając, czy zawiera pola name i email, oraz czy email ma poprawny format.

Odpowiedź ChatGPT 4o: Rozbudowana funkcja addUserToList, która sprawdza obecność name i email oraz poprawność formatu adresu e-mail.

Odpowiedź ChatGPT 4o: Rozbudowana funkcja addUserToList, która sprawdza obecność name i email oraz poprawność formatu adresu e-mail.

Obsługa wyjątków – przygotuj kod na niespodziewane błędy

Obsługa wyjątków zapewni stabilność i odporność aplikacji na niespodziewane błędy.

Takie jak: brak dostępu do plików, błędy sieciowe czy problemy z bazą danych. 

Przykładowy kod wejściowy (C#):

public string ReadFileContent(string filePath)
{
    var fileContent = File.ReadAllText(filePath);

    return fileContent;
}

🤖 Prompt

Zmodyfikuj funkcję ReadFileContent(string filePath) w C#, aby obsługiwała wyjątki związane z dostępem do pliku.

Odpowiedź ChatGPT 4o: Rozbudowana funkcja ReadFileContent, która obsługuje błędy dostępu do pliku i zwraca odpowiednie komunikaty o błędach.

Odpowiedź ChatGPT 4o: Rozbudowana funkcja ReadFileContent, która obsługuje błędy dostępu do pliku i zwraca odpowiednie komunikaty o błędach.

Zarządzanie zasobami – pamiętaj o zwalnianiu zasobów

Efektywne zarządzanie zasobami, takimi jak pliki, połączenia sieciowe czy dostęp do baz danych, jest fundamentalne dla utrzymania wydajności aplikacji i uniknięcia wycieków pamięci.

Każdy otwarty zasób systemowy, który nie zostanie prawidłowo zwolniony, może prowadzić do awarii systemu oraz degradacji wydajności. 

Przykładowy kod wejściowy (C#):

public void WriteLog(string message)
{
    StreamWriter writer = new StreamWriter("log.txt", true);

    writer.WriteLine(message);
}

🤖 Prompt

Zrefaktoryzuj funkcję WriteLog(string message) w C# z użyciem using, aby poprawnie zarządzać obiektem StreamWriter.

Odpowiedź ChatGPT 4o: Przykład zarządzania zasobami przy użyciu using w funkcji WriteLog, co zapewnia poprawne zamknięcie zasobów.

Odpowiedź ChatGPT 4o: Przykład zarządzania zasobami przy użyciu using w funkcji WriteLog, co zapewnia poprawne zamknięcie zasobów.

Praca z asynchronicznością – usprawnij przetwarzanie równoległe

Asynchroniczność jest nieoceniona przy tworzeniu responsywnych aplikacji.

Zwłaszcza przy operacjach o dużym czasie trwania, takich jak:

  • pobieranie danych z API,
  • operacje plikowe,
  • czy zapytania do bazy danych.

Przykładowy kod wejściowy (JavaScript):

function fetchData(url) {
    const response = fetch(url);

    return response.json();
}

🤖 Prompt

Przekształć funkcję fetchData(url) w JavaScript na wersję asynchroniczną z async/await.

Odpowiedź ChatGPT 4o: Asynchroniczna funkcja fetchData z async/await do bezpiecznego i wydajnego pobierania danych.

Odpowiedź ChatGPT 4o: Asynchroniczna funkcja fetchData z async/await do bezpiecznego i wydajnego pobierania danych.

Unikaj „magic numbers” – nadawaj znaczenie wartościom w kodzie

„Magic numbers” to liczby pojawiające się w kodzie bez kontekstu lub wyjaśnienia, co może utrudniać zrozumienie logiki oraz utrzymanie kodu w przyszłości.

Przypisywanie takich wartości do stałych nie tylko poprawia czytelność, ale także pozwala na łatwiejsze zarządzanie i modyfikację tych wartości w całym projekcie.

Kod będzie bardziej zrozumiały dla innych członków zespołu, a wszelkie zmiany w wartościach nie będą wymagać żmudnego przeszukiwania całego projektu.

Przykładowy kod wejściowy (JavaScript):

function calculateFinalPrice(price) {
    return price + (price * 0.2);
}

🤖 Prompt

Zrefaktoryzuj funkcję calculateFinalPrice(price), aby zamiast „magic number” 0.2 używała stałej TAX_RATE.

Odpowiedź ChatGPT 4o: Zaktualizowana funkcja calculateFinalPrice, która wykorzystuje stałą TAX_RATE zamiast 'magic number' dla lepszej czytelności.

Odpowiedź ChatGPT 4o: Zaktualizowana funkcja calculateFinalPrice, która wykorzystuje stałą TAX_RATE zamiast 'magic number' dla lepszej czytelności.

Użycie typów – zadbaj o większą pewność i jakość kodu

Typowanie, szczególnie w językach takich jak C#, znacząco podnosi jakość i stabilność kodu.

Typowanie umożliwia wczesne wykrywanie błędów związanych z niewłaściwym użyciem danych już na etapie kompilacji.

To ogranicza ryzyko wystąpienia błędów w czasie działania aplikacji.

Przykładowy kod wejściowy (C#):

public double CalculateArea(object length, object width)
{
    return (double)length * (double)width;
}

🤖 Prompt

Zmień deklaracje parametrów w funkcji CalculateArea na określone typy, aby zwiększyć bezpieczeństwo i uniknąć błędów związanych z rzutowaniem.

Odpowiedź ChatGPT 4o: Zmodyfikowana funkcja CalculateArea z określonymi typami parametrów, co zwiększa bezpieczeństwo i eliminuje potrzebę rzutowania.

Odpowiedź ChatGPT 4o: Zmodyfikowana funkcja CalculateArea z określonymi typami parametrów, co zwiększa bezpieczeństwo i eliminuje potrzebę rzutowania.

Na koniec

W artykule omówiliśmy typowe błędy programistyczne, które łatwo popełnić, a których sztuczna inteligencja skutecznie unika.

Przedstawiliśmy konkretne przykłady oraz prompty, które pomogą Ci ulepszyć kod i zwiększyć jego niezawodność.

Skupiliśmy się na dobrych praktykach, jak testowanie czy organizacja kodu – działaniach, które przekładają się na długoterminową jakość projektów.

Co dalej?

Dołącz do newslettera, by otrzymywać sprawdzone wskazówki i narzędzia przydatne w pracy programisty.

Dołącz do społeczności Programisty Przyszłości

Zapisz się, aby być na bieżąco z najnowszymi trendami, praktycznymi poradami i nowinkami technologicznymi. Zyskasz także dostęp do specjalnych promocji dostępnych wyłącznie dla subskrybentów.

Wyrażam zgodę na przetwarzanie danych osobowych zgodnie z polityką prywatności i chcę otrzymywać wiadomości komercyjne. Możesz wypisać się w dowolnym momencie 1-kliknięciem.