Bezcelowy kod w twoim źródle


34

Słyszałem o tym historie od starszych programistów i sam to widziałem. Wydaje się, że istnieje więcej niż kilka przypadków programistów piszących bezsensowny kod. Zobaczę takie rzeczy jak:

  • Wywołania metod lub funkcji, które nie mają żadnej wartości.
  • Nadmiarowe kontrole wykonane w osobnym pliku klasy, obiekcie lub metodzie.
  • if stwierdzenia, które zawsze mają wartość true.
  • Wątki, które się spinają i nic nie znaczą.

Żeby wymienić tylko kilka. Powiedziano mi, że dzieje się tak, ponieważ programiści chcą umyślnie wprowadzić kod w błąd, aby podnieść własną wartość organizacji lub zapewnić powtarzalność działalności w przypadku pracy kontraktowej lub zleconej na zewnątrz.

Moje pytanie brzmi. Czy ktoś jeszcze widział taki kod? Jaki był twój wniosek, dlaczego ten kod tam był?

Jeśli ktoś napisał taki kod, czy możesz udostępnić dlaczego?


4
if (false) {...}bloki świetnie nadają się do komentowania kodu! </sarcasm>
dlras2

18
Nigdy nie przypisuj złośliwości temu, co jest odpowiednio wyjaśnione głupotą , szczególnie w rozwoju oprogramowania, w którym tymczasowe szybkie hacki rzadko są tymczasowe.
wildpeaks

1
@ dlras2 plot twist: #DEFINE false true :)
Silviu Burcea

Odpowiedzi:


17

Słyszałem programistów, którzy starają się, aby ich osiągnięcia w kodowaniu brzmiały bardziej skomplikowane niż są w rzeczywistości. Nigdy nie słyszałem, żeby ktoś to przyznał, ale widziałem kod, który spełnia twoje kryteria, który został stworzony celowo z pośpiechu lub złych praktyk, a nie sabotażu. Kod otaczający złośliwy kod mógł zostać zmieniony do tego stopnia, że ​​dana funkcja nie jest już użyteczna.

Ktoś musiałby zobaczyć ten kod z pierwszej ręki, zanim dojdzie do wniosku, że tylko ten programista może zarządzać złożonością. Większość menedżerów i innych biznesmenów po prostu dochodzi do tego wniosku, ponieważ nie rozumie żadnego rodzaju kodu i nie chce uzupełniać stanowiska.


2
Jestem skłonny udzielić prawidłowej odpowiedzi w tym przypadku, ponieważ część kodu, który widzę, po prostu nie może być niezamierzona ... nie, chyba że ktoś był naćpany, gdy kodował i myślał, że to będzie po prostu zabawne! Wierzę, że inni mają również istotne powody, dla których kod jest bezużyteczny, ale kod, który widzę, dotyczy projektów, nad którymi pracowało kilka osób i jestem pierwszym facetem spoza oryginalnego zespołu programistów, który nad nim pracuje. Muszę powiedzieć, że wydaje się, że jest to sprawa złożoności dodana do szoku i podziwu.
Ali

18
@Ali: Nigdy nie przypisuj złośliwości, co lepiej tłumaczy niekompetencja. Innymi słowy - kod prawdopodobnie ewoluował do tego rodzaju bałaganu, ponieważ nikt nie był wystarczająco odważny, aby poświęcić czas na jego obejrzenie i zobaczenie, co faktycznie robi. To wszystko brzmi jak kilka szybkich poprawek wprowadzanych w kółko, dopóki nie pozostało tylko kupka.
szybko_nie

1
+1 za @quickly_now. Zwykle tak się dzieje; wszyscy boją się dotykać czegokolwiek, co „działa” z obawy przed złamaniem go (lub, Niebo zabrania, zajmowanie się zadaniem poprawy kodu! Horror!). Więc kod gnije i gnije, a na koniec upada wiele lat później.
Wayne Molina

@Ali, były przypadki, gdy kod, który wydaje się najbardziej semantyczny i rozsądny, został opisany, ponieważ prawdopodobnie sądzę, że jest to zabawne lub popisuję się. I odwrotnie, gdy widzę kod innych ludzi. Nigdy nie wiadomo, kto jest szalony, i przez większość czasu sprowadza się to do doświadczenia i preferencji. (nie mówiąc tutaj o obiektywnie złym kodzie, po prostu takie opisy łatwo się rzucają)
Mihail Malostanidis

73

Nie widziałem takiego kodu, ale widziałem kod, który wygląda bezcelowo lub jest bezcelowy z innych powodów:

  1. Kompatybilność wsteczna. Znalazłeś znacznie lepszy sposób na zrobienie czegoś, ale musisz zachować stary (i do tej pory niezbyt przydatny) interfejs API / funkcję, ponieważ niektóre moduły innych firm mogą do tego celu używać tego interfejsu API / funkcji. Nawet jeśli funkcja nie robi nic użytecznego, jej brak może zepsuć jakiś kod.

  2. Kodowanie obronne. Wiesz, że kontrole w tym kodzie są bezcelowe, ponieważ zostały już sprawdzone w innym miejscu. Ale co, jeśli ktoś zmieni ten kod w innym miejscu i usunie lub zmieni kontrole, aby nie spełniały twoich warunków?

  3. Wzrost organiczny. W dużych projektach z biegiem lat wiele rzeczy się zmienia i okazuje się, że niektóre metody, które były używane wcześniej, nie są już używane, ale nikt nie zadał sobie trudu, aby je usunąć, ponieważ nikt nie śledził, czy ta konkretna metoda jest używana, czy nie, po prostu dokonała refaktoryzacji ich fragmenty kodu i przez przypadek zdarzyło się, że wszyscy przestali używać tej metody. Lub warunki, które kiedyś miały znaczenie, ale aplikacja została zmieniona w innych miejscach, więc warunek ten zawsze się spełniał, ale nikt nie zadał sobie trudu, aby go usunąć.

  4. Nadmierne projektowanie. Ludzie mogą kodować niektóre rzeczy „na wypadek, gdybyśmy tego potrzebowali” i nigdy tak naprawdę nie potrzebują. Na przykład „załóżmy wątek na wypadek, gdybyśmy musieli pracować w trybie offline”, a następnie nikt nie prosi o zrobienie czegokolwiek w trybie offline, a programista zapomina o tym i przechodzi do innych projektów (a może nawet innej firmy) i ten kod pozostaje tam na zawsze, ponieważ nikt nie wie, dlaczego to istnieje lub czy można go bezpiecznie usunąć.

Tak więc, chociaż nigdy nie widziałem, aby robiono to ze złości lub niewłaściwego podejścia do bezpieczeństwa pracy, widziałem mnóstwo razy, kiedy dzieje się to jako naturalny rezultat rozwoju oprogramowania.


22
Myślę, że # 3, Organic Growth wyjaśnia dużą część Bezużytecznego Kodu, który widziałem w pracy. Ale wszystkie 4 z tych powodów zakładają inteligentnego programistę. Niektóre bezużyteczne kody wywodzą się od kogoś, kto nie rozumie, co musi się wydarzyć, a co nie, i pozostawia sporo kodu wyłącznie ze strachu przed zmianą (rodzaju) działania.
Bruce Ediger,

2
Widziałem # 4 w moim projekcie: często nie robi się tego celowo, aby mieć więcej władzy w firmie, a raczej są ludzie, którzy zawsze starają się stworzyć bardziej ogólne rozwiązanie, nawet jeśli nie jest potrzebne. Jeśli chodzi o # 2, używam go bardzo często z dokładnie tych powodów, które wyjaśniłeś: IMHO nawet najmniejsza funkcja lub metoda nie powinna przyjmować żadnych założeń co do tego, jak reszta kodu działa lub się zmieni. Zamiast tego mój kod jest zgodny z prostym wzorcem: „jeśli dane wejściowe są prawidłowe, wówczas dane wyjściowe zawierają błąd”. Jest to zgodne z ogólną zasadą projektowania polegającą na minimalizowaniu zależności.
Giorgio

3
Zapomniałeś również: złych programistów. Niektóre osoby, które piszą kod, nie powinny, a dobre procesy sprawdzania nie istnieją w wielu sklepach.
Joe

20

Moje pytanie brzmi. Czy ktoś jeszcze widział taki kod? Jaki był twój wniosek, dlaczego ten kod tam był?

1) Tak

2) W przypadkach, które widziałem, odłożyłbym to na różne sposoby:

  • Brak doświadczenia programisty
  • Programista nie rozumie szczególnie skomplikowanego i / lub źle wykonanego projektu, który próbuje zmodyfikować
  • Programator jest przerywany w środku (powiedzmy) refaktora.
  • Niedbalstwo

Być może teraz jestem z tego powodu charytatywny, ale moje ogólne podejście jest takie, że lepiej jest wybaczać / nie konfrontować się w tych sprawach, niż wskazywać palcami i mówić o złej jakości. Oczywiście, sprawy mogą stać się na tyle złe, że trzeba coś zrobić , ale zwykle wystarcza delikatny ruch we właściwym kierunku.

Oczywiście nie można przyjąć tak laissez-faire podejścia, jeśli jakość / błędy poważnie wpłyną na „biznes”. Ale w tej sytuacji potrzebujesz obowiązkowych i starannych przeglądów kodu w połączeniu z kompleksową procedurą testową.


Z mojego doświadczenia wynika, że ​​ludzie mają tendencję do „napinania się” kodem niskiej jakości (przynajmniej częściowo), ponieważ szkodzi to jego osobistym standardom. Wszystko to bardzo dobrze (osobiście) dążyć do doskonałości, ale rzutowanie osobistych standardów na innych ludzi jest nieco nierozsądne. Na podstawie dźwięków rzeczy (np. Z natury twoich przykładów) robisz to.

IMO, to nie jest produktywne i nie sprzyja dobrym stosunkom roboczym z twoimi współpracownikami.


+1 Wpisałem odpowiedź i znalazłem prawie wszystkie wymienione powody, o których chciałem wspomnieć.
canadiancreed

+1 za bycie charytatywnym. Napraw błędy kogoś bez wskazywania palcami, a koledzy będą szanować zarówno twoje umiejętności techniczne, jak i umiejętności ludzi. Harangue autora za ich gówniany kod, a twoi koledzy będą oburzeni twoim podejściem i obniżą twoje umiejętności.
Caleb

13

Wszystkie te są często objawami starzenia się projektu.

 1. Wywołania metod lub funkcji, które nie mają żadnej wartości. Często zdarza się, że jakiś kod jest po prostu taki, jaki jest (mam nadzieję, że z dużym przestarzałym ostrzeżeniem, ale ponieważ większość języków nie ma tego ostrzeżenia, nie zawsze jest przestrzegane ...), ponieważ w pewnym momencie okazało się, że prawdziwy cel i nikt nie wiedział, co mogłoby się stać, gdyby usunięto obrażające linie.

Wydaje mi się, że pamiętam to z dailywtf:

@deprecated // he might have been crazy enough to use reflection...
boolean getTrue() {
    return false; 
}

 2. Nadmiarowe kontrole wykonane w oddzielnym pliku klasy, obiekcie lub metodzie. Warstwy komunikacji są również niedoskonałe (kiedykolwiek czytałeś Miesiąc Mitycznego Człowieka? Jeśli nie, co robisz na komputerze !? Idź! CZYTAJ!). Często jedna osoba będzie nad czymś pracować, a następnie opuści projekt, a następnie kolejny facet, znajdując jakiś dziwny błąd, rzuca dodatkową kontrolę tu i tam, aby spróbować go wyeliminować. Kiedy błąd zostanie usunięty, kontrole nie są, ponieważ, cóż, jeśli nie jest zepsuty, nie naprawiaj go.

 3. jeśli stwierdzenia, które zawsze mają wartość true. Och, zrobiłem to. Raz dostałem projekt, miał serię prawdopodobnie 10-15 bloków if / else . Aby zmienić zachowanie, po prostu wstawiam true||pierwszy blok. Dopiero miesiące (lata?) Później wróciłem i powiedziałem: „Och, wow, ten kod miał zostać zniszczony, ale nigdy nie był”

 4. Wątki, które się spinają i nie robią nic wartego uwagi. Mogę sobie wyobrazić następującą myśl:

  1. Wiem! Mogę poradzić sobie z tymi dwoma problemami asynchronicznie! Stworzę wątki foo i bar.
  2. (dwa miesiące później) Huh, wiesz, funkcjonalność z baru jest trochę lepsza w foo. Przeprowadzę trochę.
  3. (rok później) Wiesz, umieszczanie tych innych rzeczy z baru w foo ma sens.
  4. (wiele, wiele lat później) „Hej, ten barwątek nie wygląda na to, że coś robi, czy możemy go usunąć?” „Lepiej nie, było tam wiele, wiele lat ...”

5
+1 za „Lepiej nie, było tam wiele, wiele lat ...” - zdarza się to w kółko. Strach przed usunięciem z obawy przed konsekwencjami („Jak sprawdzamy, czy czegoś nie złamaliśmy” - zwłaszcza jeśli nie ma w pobliżu testów jednostkowych).
szybko_nie

11

Jestem trochę bardziej optymistą. Myślę, że to, co opisałeś, często pojawia się, gdy kod jest niedokładnie zmieniany.


13
Chociaż jest to trudne, nigdy nie przypisuj Malice tego, co można wytłumaczyć głupotą.
Bruce Ediger,

8

Starzy koledzy opowiadali mi o czasach, w których konsultanci otrzymywali wynagrodzenie za liczbę wyprodukowanych linii kodu. I tak zmaksymalizowali zyski, używając niesamowicie długich konstrukcji.

W dzisiejszych czasach zawsze zakładam, że facet wciąż uczy się języka podczas wykonywania pracy. I spieszy mu się.


Mów o obcinaniu nosa na przekór twarzy. Myślę, że jest w porządku, jeśli nigdy nie będziesz musiał ponownie patrzeć na kod.
JeffO

6

Większość odpowiedzi sprowadza się do tych dwóch prostych faktów:
[1] Kod odzwierciedla historię kodu, a
[2] Kod odzwierciedla oczekiwaną przyszłość kodu.

Napisałem funkcje, które nie mają żadnej wartości, W AKTUALNYM ŚRODOWISKU APLIKACJI, biorąc pod uwagę AKTUALNE SPECYFIKACJE, ale mogą być potrzebne w przyszłości.

Napisałem instrukcje if, które NA OBECNIE zawsze oceniają jako prawdziwe. Ale może w przeszłości może to być fałsz.

Jeśli chodzi o nadmiarowe czeki, hej, nie ufam innym kodom, nawet nie ufam własnemu kodowi. Jeśli moduł zależy od tego, czy N ma wartość 1, 2 lub 3, lepiej go wypoleruj, a jeśli tak nie jest, awaria informacyjna. To nielegalne, że moduł B eksploduje, ponieważ moduł A spieprzył; uzasadnione jest, aby Moduł B narzekał, że Moduł A popsuł się. I pamiętajcie, że w przyszłym miesiącu ten parametr może pochodzić z niepisanego jeszcze modułu C.


1
Nazywam to złym kodowaniem. Oczekujesz, że będziesz go potrzebować w przyszłości, ale rzadko się to zdarza. YAGNI. Pisanie „jeśli to zawsze będzie zgodne z prawdą” to zmarnowany wysiłek i zmieszanie osoby, która na początku musi dodać całkiem inne funkcje. Ten parametr, który pojawi się w przyszłym miesiącu, może poczekać do dodania w następnym miesiącu. Zaśmiecanie kodu TERAZ jest bezcelowe.
Andy,

1
if (language = 'en' or language = th ') - może w przyszłym miesiącu spróbujemy chińskiego? if (! isset ($ TITLE)) - wszystkie moduły MUSZĄ ustawić $ TITLE, ale może ktoś kiedyś przeliteruje to źle. if (file_exists ($ TARGET)) - dobry kod już utworzył plik, ale być może wystąpił błąd systemowy i nie został utworzony. Mój standardowy kod interfejsu PHP / MySQL zawsze sprawdza pod kątem błędów, nawet jeśli jeszcze go nie złapałem.
Andy Canfield

3

Widziałem to kilka razy, właściwie dopiero wczoraj, muszę scalić kod mojego szefa z moją nową aplikacją. W jego przypadku jest to po prostu ogólny brak umiejętności i zrozumienia oraz przekonanie, że uważa, że ​​jest dość wykwalifikowanym programistą.

„Wywołania metod lub funkcji, które nie mają żadnej wartości.” oraz „jeśli stwierdzenia, które zawsze mają wartość true”, stanowią poważny problem z jego kodem.


3

Podejrzewam, że chociaż wielu widziało kod, który ma te problemy, niewielu zgodziłoby się na napisanie tego samego. Najprawdopodobniej to, co widzisz, to nagromadzone zgnilizna oprogramowania - ktoś dodaje coś, co tak naprawdę nie działa, następny opiekun dodaje kod ochronny dalej w łańcuchu, aby uchronić się przed stanem, który nie został poprawnie sprawdzony w pierwszym miejsce; wtedy ktoś otrzymuje raport o problemie i dodaje jeszcze więcej zbroi do konkretnego wystąpienia problemu; inna osoba dodaje bardziej ogólną kontrolę i zapomina usunąć część wcześniej dodanego wcześniej kodu, który dotyczył bardziej specyficznych objawów itp.

Potem jest problem z czyszczeniem kodu: nie ma szczególny bodziec do usunięcia, co wydaje się być martwy kod, a ogromna zachęta nie robić, bo jeśli nie rozumieją kod całkowicie swoją ocenę, że kod jest „martwa” będzie bądź wadliwy, a skończysz na zerwaniu systemu.


2
  • Wywołania metod lub funkcji, które nie mają żadnej wartości.

Niekoniecznie źle. Metody w klasie bazowej często wywołują puste metody, które mają służyć jako punkty zastępujące podklasy. Przykład: UIView Cocoa Touch ma -didAddSubview:metodę udokumentowaną jako brak działania w wersji domyślnej. -addSubview:Metoda UIView musi wywoływać, -didAddSubview:nawet jeśli nic nie robi, ponieważ podklasy mogą ją zaimplementować, aby coś zrobić. Metody, które nic nie robią i ich powody powinny być oczywiście udokumentowane.

Jeśli pusta lub bezużyteczna funkcja / metoda jest oczywiście dostępna z przyczyn historycznych, należy ją wyciąć. Jeśli nie jesteś pewien, spójrz na wcześniejsze wersje kodu w repozytorium kodu źródłowego.

  • Nadmiarowe kontrole wykonane w osobnym pliku klasy, obiekcie lub metodzie.

Trudno powiedzieć, czy to w porządku bez kontekstu. Jeżeli kontrole są wyraźnie wykonywane z tego samego powodu, może to oznaczać, że nie ma wyraźnego podziału obowiązków i konieczne jest dokonanie refaktoryzacji, szczególnie gdy obie kontrole skutkują tym samym działaniem. Jeśli akcja wynikająca z obu kontroli nie jest taka sama, to prawdopodobnie dwie kontrole są wykonywane z różnych powodów, nawet jeśli warunek jest taki sam, i prawdopodobnie jest to w porządku.

  • jeśli instrukcje, które zawsze mają wartość true.

Istnieje duża różnica między:

if (1) {
    // ...
}

i:

if (foo() == true) {
    // ...
}

gdzie foo()zdarza się zawsze wracać true.

Pierwszy przypadek zdarza się często, gdy ludzie debugują. Łatwo jest użyć if (0) {...tymczasowo usunąć kawałek kodu, podczas gdy starasz się wyizolować problem, a następnie zmienić 0na 1przywrócenie tego kodu. ifPowinny zostać usunięte po skończysz, oczywiście, ale to łatwo zapomnieć, że krok, albo do pominięcia jednej lub dwóch, jeśli zrobiłeś to w kilku miejscach. (Dobrym pomysłem jest identyfikowanie takich warunków z komentarzem, który można później wyszukać). Jedyną szkodą jest zamieszanie, które może powodować w przyszłości; jeśli kompilator może określić wartość warunku w czasie kompilacji, usunie go całkowicie.

Drugi przypadek może być do zaakceptowania. Jeśli warunek reprezentowany przez foo()musi zostać przetestowany z kilku miejsc w kodzie, faktoryzacja go w osobnej funkcji lub metodzie jest często słuszna, nawet jeśli foo()zawsze dzieje się tak teraz. Jeśli można sobie wyobrazić, że foo()może to w końcu powrócić false, to izolowanie tego warunku w metodzie lub funkcji jest jednym ze sposobów identyfikacji wszystkich miejsc, w których kod opiera się na tym warunku. Takie postępowanie stwarza jednak pewne ryzyko, że foo() == falsestan ten nie zostanie przetestowany i może później spowodować problemy; rozwiązaniem jest upewnienie się, że dodano testy jednostkowe, które jawnie testują falseobudowę.

  • Wątki, które się spinają i nic nie znaczą.

Brzmi to jak artefakt historii i coś, co można zidentyfikować podczas przeglądu kodu lub poprzez okresowe profilowanie oprogramowania. Przypuszczam, że można to zrobić celowo, ale trudno mi sobie wyobrazić, że ktoś faktycznie zrobiłby to celowo.


1

Zdarza się. W rzeczywistości dość często.

Czasami te ślepe zaułki kodowania są bardziej jak stare kozie ślady, które popadły w ruinę, gdy wokół nich zainstalowano bardziej wydajną / nowoczesną / szybką autostradę.

Przy innych okazjach (i prawdopodobnie jestem tego winien) są one podstawą do rozszerzenia oprogramowania, gdy wymagany jest krótki, ale niepotwierdzony zestaw funkcji / funkcji. (Czasami wkładanie odrobiny pracy w początkową wersję, dostarczanie uchwytów i tym podobnych do późniejszej pracy, którą planujesz „przykręcić”, może ułatwić życie, gdy się zdarzy, lub trudniejsze / bałagan, jeśli dalsza praca nie w końcu.)

I wiele z tego wynika bezpośrednio ze starego „Jeśli się nie zepsuło, nie pasuj”. Czasami odrywanie kodu, którego nie rozumiesz lub uważasz, że jest nieużywany, może spowodować programową wersję „The Butterfly Effect”. Miałem to raz lub dwa razy.


1

Czasami mam globalną wartość logiczną ustawioną na true, a później w moim kodzie i (bool), a następnie w czasie wykonywania mogę ustawić punkt przerwania w instrukcji if i zmienić wartość logiczną, aby coś przetestować.


0

Sprzeciwiam się, aby if trueoświadczenia były bezkrytycznie klasyfikowane jako „bezsensowny kod”.

Istnieje uzasadniony przypadek użycia if (1) { ... }bloku w kodzie C, który albo chce być zgodny ze standardem C, który nalegał, aby definicje zmiennych znajdowały się na początku funkcji, albo po prostu chce, aby zmienne lokalne były zdefiniowane tak lokalnie, jak to możliwe.

switch (i) {
    case 23:
        if (1) {
            /* I can declare a local var here! */
        }
        break;
}

5
Nie ma potrzeby „jeśli (1)”, dlaczego po prostu nie mieć bloku?
FigBug

3
Zarówno C / C ++, jak i C # i jestem prawie pewien, że Java (jak również prawdopodobnie wiele innych podobnych języków) pozwala na anonimowe bloki instrukcji; Nie potrzeba opracowania if, whilelub podobna konstrukcja. Jest mało prawdopodobne, aby był bardzo czysty, ale z pewnością jest dozwolony zgodnie ze specyfikacją języka.
CVn

0

Mój profesor opowiedział nam kiedyś historię, że poprzedni pracodawca zapłaci im na podstawie liczby wypełnionych wierszy. Napisali więc kilka funkcji z wieloma tuzinami, które nigdy nie zostały wywołane. Wydaje się, że to świetny powód do pisania bezsensownego kodu.


0

Jak wspomniałem @Andy, dużym elementem, który widziałem, jest łamanie YAGNI .

Ktoś zaczyna od założenia, czym będą wszystkie elementy zamiast tego, czego może potrzebować wiele elementów , co jest pomieszaniem relacji „jest” i „ma” .

To zamieszanie prowadzi do sztywnej struktury dziedziczenia, a następnie są to metody, które nie zostały zaimplementowane, ponieważ nigdy nie są wywoływane, powtarzana logika, w której należało dostosować części, i po prostu dziwne przepływy pracy, które nie pasują do modelu biznesowego.

Podobnie jak wielu innych tutaj, nie widziałem, aby zrobiono to złośliwie, ale z powodu braku wiedzy na temat dobrego projektu i próby sprawienia, aby wyglądało to tak, jak inni. Zabawne, wydaje się, że programiści, nawet mniej znający się na rzeczy, wydają się radzić sobie lepiej pod tym względem, ponieważ przynajmniej ich kod nie kończy się zbytnio skonstruowanym ad naseum. ( Zasada KISS )

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.