świstak.codes

O programowaniu, informatyce i matematyce przystępnym językiem

(prawie) Codzienny wtręt programisty (31-40)

(prawie) Codzienny wtręt programistyczny to seria krótkich wpisów na moich social mediach, gdzie dzieliłem się krótkimi radami i przemyśleniami na temat programowania. W tym artykule znajdziesz spisane treści wpisów o numerach od 31 do 40.

Wstęp

Treści, które tutaj zobaczysz, oryginalnie były publikowane na moich social mediach. Są nieco inne niż tematyka tego bloga: porady dla osób zaczynających pracę w IT oraz rzeczy związane typowo z front-endem i JavaScriptem. Blog z założenia miał być zawsze bardziej ogólny, skupiający się na uniwersalnej wiedzy z zakresu informatyki niezależnie od technologii, wykształcenia i zawodu.

Jeśli chciałbyś/chciałabyś być na bieżąco z podobnymi treściami, zapraszam do obserwowania moich social mediów:

#31 4 sposoby na zaokrąglanie liczb

Wiesz, że klasycznie w językach programowania mamy 4 sposoby na zaokrąglanie liczb zmiennoprzecinkowych do całkowitych? Zobacz kolejne obrazki i dowiedz się, czym każda z tych opcji się różni.

A Ty których najczęściej używasz i dlaczego?

Round — zaokrąglenie do najbliższej wartości

Math.round(2.1); // 2
Math.round(3.7); // 4
Math.round(5.5); // 6
Math.round(-2.1); // -2
Math.round(-3.7); // -4
Math.round(-5.5); // -5

Warto zwrócić uwagę, jak w Twoim języku programowania traktowany jest przypadek piątki po przecinku!

Floor — podłoga; zaokrąglenie w dół

Math.floor(2.1); // 2
Math.floor(3.7); // 3
Math.floor(5.5); // 5
Math.floor(-2.1); // -3
Math.floor(-3.7); // -4
Math.floor(-5.5); // -6

Uwaga: nie jest to obcięcie części dziesiętnej! Zobacz przykłady dla liczb ujemnych.

Ceil — sufit; zaokrąglenie w górę

Math.ceil(2.1); // 3
Math.ceil(3.7); // 4
Math.ceil(5.5); // 6
Math.ceil(-2.1); // -2
Math.ceil(-3.7); // -3
Math.ceil(-5.5); // -5

Truncate — obcięcie części dziesiętnej

Math.trunc(2.1); // 2
Math.trunc(3.7); // 3
Math.trunc(5.5); // 5
Math.trunc(-2.1); // -2
Math.trunc(-3.7); // -3
Math.trunc(-5.5); // -5

#32 Czy umiemy się uczyć?

Mówi się, że praca w IT to ciągły rozwój, potrzeba stałej nauki. Warto jednak zadać sobie pytanie, czy umiemy się uczyć?

Moim zdaniem można zauważyć trzy główne problemy, przez które czy to studiując, czy robiąc kursy, niewiele z tego wynosimy. Sam zresztą miałem okazje przez nie przejść.

Wkuwamy teorię zamiast zrozumieć

  • ➡️ Typowo szkolne 3Z: „zakuć, zdać, zapomnieć”.
  • ➡️ Faza „zapomnieć” zwykle zachodzi bardzo szybko.

Uczymy się gotowych rozwiązań bez teorii

  • ➡️ Szczególnie zauważalne przy tutorialach z Internetu.
  • ➡️ Interesuje nas tylko rozwiązanie problemu, a nie jego sedno.
  • ➡️ Zapamiętane rozwiązania rzadko można przełożyć na ogólny przypadek.

Uczęszczamy w szkoleniach dla „papierka”

  • ➡️ Nie uczestniczymy aktywnie w szkoleniu.
  • ➡️ Mimo że kojarzy się z uczelniami wyższymi, to często odnosi się to też do szkoleń branżowych kończących się certyfikatem.

#33 Reszta z dzielenia jest dziwna

O ile dla liczb dodatnich reszta z dzielenia jest niemal zawsze taka sama, to problemy zaczynają się, gdy pojawiają się liczby ujemne. Różne języki implementują inne sposoby jej obliczania, stąd wyniki się różnią i do tego są nie do końca zgodne z matematyczną definicją tego działania.

Zobacz dalej, jakie wyniki operacja ta daje w różnych językach.

Jeśli chcesz wiedzieć, skąd to się bierze, a także jak uzyskać tę matematyczną wersję, zapraszam do lektury: https://swistak.codes/post/dziwny-przypadek-reszty-z-dzielenia/

Dart

void main() {
  print('8 mod 5 = ${8 % 5}');
  print('-8 mod 5 = ${-8 % 5}');
  print('8 mod -5 = ${8 % -5}');
  print('-8 mod -5 = ${-8 % -5}');
}

// 8 mod 5 = 3
// -8 mod 5 = 2
// 8 mod -5 = 3
// -8 mod -5 = 2

Python

print(f'8 mod 5 = {8 % 5}')
print(f'-8 mod 5 = {-8 % 5}')
print(f'8 mod -5 = {8 % -5}')
print(f'-8 mod -5 = {-8 % -5}')

# 8 mod 5 = 3
# -8 mod 5 = 2
# 8 mod -5 = -2
# -8 mod -5 = -3

JavaScript

console.log(`8 mod 5 = ${8 % 5}`);
console.log(`-8 mod 5 = ${-8 % 5}`);
console.log(`8 mod -5 = ${8 % -5}`);
console.log(`-8 mod -5 = ${-8 % -5}`);

// 8 mod 5 = 3
// -8 mod 5 = -3
// 8 mod -5 = 3
// -8 mod -5 = -3

#34 Mniej oczywiste korzyści unit testów

W kontekście testów jednostkowych zawsze się mówi, że możemy dzięki nim sprawdzić kod, czy poprawnie się wykonuje. To prawda, ale nie jest to jedyna korzyść, jaką one dają.

Żywa dokumentacja

  • ➡️ Dobrze napisane testy spełniają funkcję podobną do dokumentacji.
  • ➡️ Patrząc na test, jesteś w stanie lepiej wywnioskować, co autor miał na myśli.

Wymuszają pisanie ładnych funkcji

  • ➡️ Nie da się łatwo napisać testów dla funkcji wykonujących wiele rzeczy (łamanie SRP).
  • ➡️ Tak samo nie da się łatwo testować funkcji z efektami ubocznymi.

Wymuszają dobre konwencje architektoniczne

  • ➡️ Jeśli nie stosuje się odwrócenia zależności, doprowadzenie mocków do działania może zająć więcej miejsca niż testy.
  • ➡️ Zmuszają do rozdzielania kodu na mniejsze jednostki, które łatwiej się testuje (np. na front-endzie wydzielenie logiki komponentów na zewnątrz).

#35 Pamiętaj o tym, tworząc nowy projekt JS-owy

Jeśli zakładasz nowy projekt JS-owy, pamiętaj o konfiguracji trzech narzędzi, które sprawią, że kod będzie spójny, czytelny, a także ułatwią Ci sprawdzanie pull requestów.

ESLint

  • ➡️ Statyczna analiza kodu.
  • ➡️ Umożliwia uwspólnienie stylu kodowania bez ręcznego spisywania zasad.

Prettier

  • ➡️ Automatyczne formatowanie kodu.
  • ➡️ Zapewnia czytelny i spójny kod pod kątem formatowania.

EditorConfig

  • ➡️ Narzuca edytorowi reguły formatowania.
  • ➡️ Przydatny tam, gdzie Prettier i ESLint nie potrafią działać, np. na plikach konfiguracyjnych.

Jak z nimi pracować?

  • ➡️ Sprawdzanie jako kroki pipeline CI.
  • ➡️ Git Hook na pre-commit (np. korzystając z Husky).
  • ➡️ Wtyczki do edytorów, aby podświetlały błędy i je automatycznie naprawiały.

#36 Złożoność cyklomatyczna a unit testy

Złożoność cyklomatyczna to jedna z podstawowych metryk wskazujących poziom skomplikowania pisanego przez nas kodu. Co ciekawe, ma ona wpływ na pisanie unit testów. Czytaj dalej, aby dowiedzieć się, w czym rzecz!

Złożoność cyklomatyczna

  • ➡️ Liczba mówi, ile różnych ścieżek przejścia kodu jest w danej funkcji.
  • ➡️ Im wyższa, tym bardziej skomplikowany jest nasz kod.
  • ➡️ Powinniśmy pisać kod tak, aby wartość była jak najniższa

Jak liczyć?

  • ➡️ Każde zwrócenie wartości daje złożoność 1.
  • ➡️ Każda instrukcja przepływu sterowania (warunki, pętle) zwiększa złożoność o 1.
  • ➡️ Możesz stosować wtyczki do edytorów, np. CodeMetrics do VSCode.

Przykład

Co to ma do unit testów?

  • ➡️ Zakłada się, że aby funkcję przetestować poprawnie, powinna ona mieć tyle testów, co jej złożoność cyklomatyczna.
  • ➡️ Jeśli masz tyle testów, ile wynosi złożoność cyklometryczna, to powinieneś/powinnaś mieć 100% branch coverage.

#37 3 lata świstak.codes

Nietypowo dzisiejszy wtręt jest bardziej o mnie, bo właśnie wybija trzecia rocznica założenia mojego bloga świstak.codes. Na slajdach poniżej kilka faktów z 3 lat istnienia. A jeśli jeszcze nie miałeś(-aś) okazji go poczytać, to zapraszam na https://swistak.codes !

Początki

Blog początkowo był oparty na Wordpressie i wyglądał tak:

Zrzut ekranu ze starej wersji strony świstak.codes

Dziś

Dziś jest przeze mnie napisany od zera w Next.js. Przepisanie zajęło mi 3 miesiące i opisałem je w tym artykule:

Okładka artykułu 'świstak.codes powraca'
https://swistak.codes/offtopic/swistak-codes-powraca/

Jeszcze wcześniej...

Rok przed założeniem świstak.codes publikowałem na Medium:

Zrzut ekranu mojego profilu na Medium

https://tomasz-swistak.medium.com/

Social media

Początkowo wystartowałem tylko z blogiem. Dziś świstak.codes to też profil na Facebooku i Instagramie.

Kto wie, może niedługo będzie coś więcej?

A teraz trochę statystyk

statystyki na moment oryginalnej publikacji wpisu, czyli 28.04.2023
  • ➡️ Na blogu znajdziecie 71 artykułów, kolejny już 10 maja!
  • ➡️ Przez ostatni rok bloga odwiedziło ponad 41 tysięcy unikalnych odwiedzających (licząc tylko tych, którzy nie blokują analityki).
  • ➡️ W Google zaś linki do bloga były klikane ponad 45 tysięcy razy.

Najczęściej odwiedzany artykuł

Okładka artykułu 'Określanie dnia tygodnia dla dowolnej daty'
https://swistak.codes/post/okreslanie-dnia-tygodnia-dla-dowolnej-daty/

Ciekawostka

Zrzut ekranu z Google po wpisaniu frazy 'jak określić dzień tygodnia dla daty'

Nie dziwię się, że jest odwiedzany, bo sam bym nic nie wyciągnął z tego fragmentu 😀

Najrzadziej odwiedzany artykuł 😢

Okładka artykułu 'Jak komputer rysuje okręgi'

https://swistak.codes/post/jak-komputer-rysuje-okregi/

Dajcie mu trochę miłości i go odwiedźcie!

Jeszcze na koniec...

Zapraszam do regularnych odwiedzin!

Zrzut ekranu strony głównej bloga

Nowe artykuły wrzucam co 2 tygodnie.

#38 Programowanie z AI

Wielu pokazuje, jak wspomagać się w pracy programistycznej ChatGPT. Ja jednak chciałem Ci przedstawić inne narzędzie: www.phind.com.

Zobacz kolejne obrazki, gdzie opisuję, co to za narzędzie, i pokazuję przykłady, jak działa.

Co to jest phind.com?

Zrzut ekranu z phind.com
  • ➡️ Wyszukiwarka dla programistów operująca językiem naturalnym.
  • ➡️ Oparta na GPT-4.
  • ➡️ Pisze rozbudowane odpowiedzi z odnośnikami do źrodeł (StackOverflow, blogi programistyczne, dokumentacje).
  • ➡️ Łączy wiedzę z różnych źródeł, dając unikalne wyjaśnienia.

A co możemy w nim zrobić? Zobacz dalej przykłady ⏭️

Implementacje algorytmów wraz z wyjaśnieniami

Zrzut ekranu z phind.com po wpisaniu frazy 'How to write quick sort in Common Lisp?'

Dokumentacja funkcji

Zrzut ekranu z phind.com po wpisaniu frazy 'What is Math.clz32() in JavaScript?'

Przykłady użycia bibliotek

Zrzut ekranu z phind.com po wpisaniu frazy 'How to use prettytime library in Kotlin?'

Ciekawe pomysły

Zrzut ekranu z phind.com po wpisaniu frazy 'What is the best way to hide an easter egg in a corporate app?'

Nawet potrafi pisać muzykę

Zrzut ekranu z phind.com po wpisaniu frazy 'How to play Darude Sandstorm in Sonic Pi?'

(tak naprawdę to nie umie 😀)

I nie ogranicza się tylko do tematów technicznych

Zrzut ekranu z phind.com po wpisaniu frazy 'What's the best place to live as an expat?'

#39 Usuwanie domyślnych stylów

Pracując na frontendzie, prawie zawsze trafiamy na problem, gdzie napisaliśmy bardzo ładnego CSS-a, ale nie działa on tak, jakbyśmy tego chcieli, bo przeglądarka narzuca własne style.

Jeśli chcesz poznać dwa sposoby na usunięcie domyślnych stylów, czytaj dalej.

Gotowe stylesheety resetujące wszystko

Usunięcie stylów pojedynczego elementu:

element {
  all: unset;
}

Przykład

Z lewej strony element z domyślnymi stylami, z prawej z usuniętymi.

#40 Powtarzanie kodu w testach jest OK

Często się mówi, że powinniśmy nie powtarzać kodu, unikać robienia kopiuj-wklej. Zamiast tego powinniśmy uwspólniać jak najwięcej kodu. Zgoda, ale nie zawsze powinniśmy.

Przeczytaj dalej, dlaczego w przypadku testów warto czasem powielić kod.

Ta sama akcja, ale testujemy coś innego

  • ➡️ Testując, nieraz mamy sytuację, że wywołanie funkcji jest takie samo, tylko przyjmuje inne dane. Nawet asercja może wyglądać tak samo.
  • ➡️ Jednak inne dane mogą oznaczać zupełnie inny przypadek, który powinniśmy inaczej opisać.
  • ➡️ Pamiętaj: testy mają funkcję dokumentacji. Najpierw opisz wszystkie przypadki, a potem napisz do nich kod. Nawet duplikujący się, to nie jest nic złego!

Przykład

  • ➡️ Mamy funkcję konwertującą kolor do wspólnego formatu: normalizeColor(color: string): string.
  • ➡️ Niezależnie od tego, w którym formacie kolor zostanie podany na wejściu, wyjście powinno zawsze zwrócić ten sam format (załóżmy, że hex zapisany dużymi literami).
  • ➡️ Zakładamy, że jeśli nie potrafi przekonwertować formatu (nieobsługiwany lub błędne wejście), zwracamy to samo, co było na wejściu.

Moglibyśmy wszystko zamknąć w jednym teście

it.each`
  color                | expected
  ${'#b4cd12'}         | ${'#B4CD12'}
  ${'#b4c'}            | ${'#B4C'}
  ${'rgb(255,0,0)'}    | ${'#F00'}
  ${'hsl(68 73% 60%)'} | ${'#D0E34F'}
  ${'aquamarine'}      | ${'aquamarine'}
`('should normalize colors', ({ color, expected }) => {
    expect(normalizeColorValue(color)).toEqual(expected);
  });

Ale lepiej będzie podać konkretne przypadki:

it.each`
  color                | expected
  ${'#b4cd12'}         | ${'#B4CD12'}
  ${'#b4c'}            | ${'#B4C'}
`('should uppercase hex colors', ({ color, expected }) => {
    expect(normalizeColorValue(color)).toEqual(expected);
  });

it.each`
  color                | expected
  ${'rgb(255,0,0)'}    | ${'#F00'}
`('should convert rgb to uppercased hex', ({ color, expected }) => {
    expect(normalizeColorValue(color)).toEqual(expected);
  });

it.each`
  color                | expected
  ${'hsl(68 73% 60%)'} | ${'#D0E34F'}
`('should convert hsl to uppercased hex', ({ color, expected }) => {
    expect(normalizeColorValue(color)).toEqual(expected);
  });

it.each`
  color                | expected
  ${'aquamarine'}      | ${'aquamarine'}
`('should return the same if not supported', ({ color, expected }) => {
    expect(normalizeColorValue(color)).toEqual(expected);
  });

Dlaczego tak?

  • ➡️ Dokumentujemy funkcję: pokazujemy wprost, co ona obsługuje.
  • ➡️ Dodatkowo wyszczególniamy konkretnie, co robi.
  • ➡️ Wyraźnie wskazujemy nieobsługiwane przypadki.
  • ➡️ W przypadku regresji łatwiej jest wskazać, który przypadek przestał działać.
Zdjęcie na okładce wygenerowane z użyciem DALL-E.