Czy można używać metaprogramowania, mimo że nie wszyscy to rozumieją?


102

Stosuję wiele metaprogramowania, aby uniknąć powtarzalnych zadań i budować bezpieczniejsze w użyciu abstrakcje.

Niedawno przeniosłem się do nowej pracy, w której pracuję w większym zespole i martwi to niektórych moich kolegów, ponieważ oni tego nie rozumieją.

Zawsze staram się wykorzystać pełny potencjał języka, ale niektórzy (nie wszyscy) moi koledzy postrzegają to jako ryzyko (niektórzy z zadowoleniem przyjmują takie podejście).

Zgadzam się, że pisanie kodu jest problemem, którego nikt inny w zespole nie jest w stanie zrozumieć. Z drugiej strony wszyscy jesteśmy profesjonalnymi programistami C ++ i myślę, że powinniśmy dążyć do wyższego standardu niż pisanie C za pomocą klas.

Moje pytanie brzmi: kto ma rację, co powinienem zrobić?

Wyjaśnienie: Próba wykorzystania pełnego potencjału języka nie oznacza, że ​​rzucam TMP przy każdym problemie. C ++ jest zestawem narzędzi, a dla mnie biegłość w C ++ polega na tym, że mogę korzystać ze wszystkich narzędzi z pudełka i wybierać odpowiednie dla konkretnego zadania.


38
Jest to ostatecznie oparte na opiniach. Osobiście ustalam, że nie należy używać funkcji tak złożonych, że przypadkowo są one kompletne w Turinga - takich jak metaprogramowanie szablonów C ++.
Kilian Foth

24
@KilianFoth szablony nie są „przypadkowo” kompletne w Turingu. Zawsze miały być potężnymi narzędziami abstrakcji
Caleth

73
Kod, którego nikt nie rozumie, nie jest wyższym standardem.
gburton

37
@Caleth Herb Sutter nazywa je przypadkowo Turing-complete . Jasne, miały one być potężnymi funkcjami abstrakcyjnymi, ale nie sądzę, aby były przeznaczone na tak tajemne, nierozstrzygalne konstrukcje, na jakie pozwala kompletność Turinga. I z pewnością ich składnia nie została zaprojektowana, aby takie metaprogramowanie było mniej przejrzyste, niż było to konieczne.
leftaroundabout

26
Fałszywa dychotomia. Możesz programować w „wyższym standardzie” i pozostawić C z klasami, zastosować nowoczesne C ++, używać szablonów (np. STL), a także const, no () casting, bez arytmetyki wskaźnika, semantyki wartości, dużo dobroci, bez nagłówka ibnto TMP. Jeśli nie widzisz światła dziennego między C-z-klasami i TMP, robisz to źle.
Kate Gregory,

Odpowiedzi:


185

Metaprogramowanie jest OK. To, co próbujesz zrobić, nie jest w porządku.

W pracy stale używam metaprogramowania. To potężne narzędzie, którego można używać do robienia wielu rzeczy w bardziej czytelny i łatwy do utrzymania sposób. Jest to również jeden z trudniejszych do zrozumienia stylów programowania, więc naprawdę musi na tym zapracować. Podoba mi się, gdy mogę zmniejszyć 1000 wierszy kodu do 50, ale staram się go ograniczyć jako taki.

Problemem nie jest metaprogramowanie, ale to:

Z drugiej strony wszyscy jesteśmy profesjonalnymi programistami C ++ i myślę, że powinniśmy dążyć do wyższego standardu niż pisanie C za pomocą klas.

Tutaj masz kłopoty. Masz opinię Dobrze jest mieć opinię, że metaprogramowanie jest dobre. Dobrze jest mieć opinię, że wszyscy powinniśmy dążyć do bycia lepszymi programistami C ++.

Zmuszanie zarówno współpracowników, jak i przyszłych pracowników, którzy będą musieli zachować kod, który napisałeś, jest zgodne z twoją opinią. To jest praca twojego szefa. Twój szef powinien dbać o to, aby Twój kod był łatwy do utrzymania na dłuższą metę. Mają (miejmy nadzieję) większe doświadczenie biznesowe, ponieważ wierzcie mi, kiedy mówię, że jest to decyzja biznesowa, a nie ideologiczna.

Dobrze jest mieć metaprogram. Dobrze jest uczyć innych metaprogramu. Ale zrozumcie, że innym może również nie chcieć uczyć się metaprogramu i będzie to prawdą, dopóki nie osiągniecie władzy. (i jako tajemnica branżowa: kiedy w końcu jesteś wiodącym programistą, na stanowisku władzy, wcale nie jesteś na stanowisku władzy. Jest ktoś, kto kontroluje portfele, które są u władzy).

Jeśli chcesz zachęcić ich do korzystania z metaprogramowania, zacznij od małych . Zacznij od jednego, enable_ifktóry ułatwia czytanie interfejsu API. Następnie skomentuj światło dzienne . Następnie może znaleźć jeden przypadek, w którym metafunkcja szablonu zamienia 10 dużych powtarzalnych klas w 1 klasę z 10 małymi pomocnikami. Skomentuj, do diabła, z tego. Otrzymać odpowiedź. Znajdź, co ludzie o tym myślą. Bądź w porządku, jeśli powiedzą ci, żebyś tego nie robił. Znajdź niszę, w której metaprogramowanie zarabia tak bardzo, że wszyscy twoi koledzy (niechętnie) zgadzają się, że było to właściwe narzędzie do tego zadania.

Krótko mówiąc, napisałem kiedyś piękną bibliotekę, stosując obszerne metaprogramowanie. Zrobił dokładnie to, czego potrzebowaliśmy w tym czasie, kiedy żadne inne podejście nie mogło się zdalnie zamknąć. To zmieniło kierunek aplikacji, w której pisałem. Ale to było metaprogramowanie. Tylko jedna lub dwie inne osoby w mojej firmie mogły to przeczytać.

Później mój kolega po raz kolejny spróbował rozwiązać problem. Zamiast wykorzystywać metaprogramowanie do precyzyjnego robienia tego, co było potrzebne, pracował z kierownictwem, aby złagodzić ograniczenia nałożone na problem, tak że metaprogramowanie nie było potrzebne. Być może bardziej dokładnie, metaprogramowanie było mniej potrzebne. Był w stanie ograniczyć to do tego, co najlepiej wykonuje metaprogramowanie.

Powstała biblioteka jest teraz w stanie być wykorzystywana na niezwykle szerokim rynku, a to z pewnością w niemałej części ze względu na fakt, że nowy kod może być utrzymywany przez znacznie szerszą gamę programistów. Jestem dumny z tego, że toruję drogę metaprogramowaniu, ale to kod mojego kolegi dociera do szerszej publiczności, i są ku temu dobre powody.


72
Zamień „metaprogramowanie” na inny styl, technikę, technologię, bibliotekę, a odpowiedź jest nadal świetna!
Andrejs,

4
Twój szef powinien dbać o to, aby Twój kod był łatwy do utrzymania na dłuższą metę. Większość szefów nawet nie wie, czym jest łatwość utrzymania kodu. Nie mają praktycznie żadnej wiedzy technicznej, więc nie ufałbym ich decyzjom, które mają raczej charakter polityczny.
t3chb0t

4
@ t3chb0t: Doświadczony szef wie, ile pieniędzy należy wydać na obsługę klienta (tj. naprawę błędów i nowe funkcje) i jak zminimalizować ten koszt. Utrzymanie jest najpotężniejszym narzędziem do tego celu. Ten szef może nie znać szczegółów technicznych, ale powinien być w stanie zbudować zespół, któremu można zaufać w tym momencie.
mouviciel

25
@DDrmmr Ustawiłem ton dla kogoś, kto uważa, że ​​programiści powinni używać metaprogramowania, aby podnieść standard. Nie sądzę, że należy go sprowadzić do miejsca, w którym może go utrzymać najmniej wykwalifikowany członek zespołu. Należy go ogłuszyć do miejsca, w którym zespół może go utrzymać, a być może nawet silniej, należy go ogłuszyć do miejsca, w którym zespół może go utrzymać bez ciebie . W przeciwnym razie pisze się pracę.
Cort Ammon

15
@Joshua Odkryłem, że nie istnieje coś takiego jak „kod, który nie wymaga konserwacji”.
Cort Ammon

39

Przede wszystkim jest to problem zespołu i musisz go rozwiązać z zespołem. Jeśli masz kopię zapasową od zespołu do programowania przy użyciu określonych elementów i konstrukcji, zrób to; jeśli nie, przedyskutuj to z nimi, a jeśli nie będziesz w stanie ich przekonać i uzasadnić, dlaczego „twoje podejście” jest wyraźnie lepsze, lepiej nie będzie go używać.

Zauważ, że używanie metaprogramowania szablonów w C ++ jest zawsze kompromisem: jasne, czasami może pomóc zaprojektować pewne części aplikacji bardziej SUCHE i zdecydowanie jest pomocne w tworzeniu wysoce wydajnych i wielokrotnego użytku bibliotek.

Z drugiej strony, korzyści te są w pewnym kosztem: kod staje się bardziej abstrakcyjne, często znacznie trudniejsze do odczytania, znacznie trudniejszy do debugowania i znacznie trudniejsze do utrzymania. To sprawia, że ​​przydatność metaprogramowania w programowaniu aplikacji jest często wątpliwa. Zakładając, że nie zamierzasz tworzyć następnego STL, za każdym razem, gdy masz ochotę korzystać z metaprogramowania, zadaj sobie pytanie, czy te wady są tego warte. A jeśli nie jesteś pewien, przedyskutuj to z recenzentem podczas recenzji kodu.


Zgadzam się, ale omawiam to z QA, zanim umieścisz to w kodzie. Nie ma sensu tworzyć czegoś, co zostanie odrzucone.
shawnhcorey

8
Co powiesz na: „Zgadzam się. Ale…” Zmiana na „na” całkowicie zmienia znaczenie. Zawsze należy omówić z QA coś niezwykłego, zanim poświęci się temu czas. Stwierdziłeś, że ta dyskusja powinna odbyć się podczas przeglądu kodu, po upływie czasu.
shawnhcorey

@shawnhcorey: jasne, jeśli „QA” w Twojej organizacji jest odpowiedzialne za standardy kodowania. Jednak nie jest to typowa rola „QA” IMHO - w większości organizacji, które znam, termin „QA” odnosi się do grupy osób, które zapewniają kontrolę jakości w czarnej skrzynce, nie odpowiadając za które elementy języka programowania powinny być używane, a które nie. Ci ludzie rzadko są wystarczająco wykwalifikowani w programowaniu, aby omówić takie szczegóły.
Doc Brown

2
@shawnhcorey: właśnie o to mi chodzi, rola kontroli jakości różni się znacznie w różnych organizacjach. W wielu organizacjach osoby odpowiedzialne za kontrolę jakości nie mają pojęcia o programowaniu, więc prawdopodobnie nie są odpowiednie do omawiania takiego tematu.
Doc Brown

2
@shawnhcorey: cóż, z jednej strony napisałeś: „QA to termin ogólny” - z drugiej strony masz bardzo specyficzną rolę i odpowiedzialność w zakresie kontroli jakości - brzmi to dla mnie trochę sprzeczne.
Doc Brown

18

Moja ogólna opinia: jeśli masz wybór, jak to często bywa, pomiędzy trzema następującymi opcjami:

  • Ręcznie powtarzaj wiele nietrywialnych struktur kodu;
  • Użyj metaprogramowania szablonów C ++ do automatyzacji generowania kodu;
  • Użyj innego mechanizmu generowania kodu, takiego jak makra lub inny język programowania, aby wygenerować pliki źródłowe C ++

wtedy prawidłowo wykonane metaprogramowanie szablonu będzie prawdopodobnie najbardziej czytelne i możliwe do utrzymania z trzech opcji. To argument, który przedstawiłbym zespołowi, gdybym był na twoim miejscu. Przykłady z rzeczywistym kodem pomogłyby je przekonać.

Kiedy używasz Metaprogramowania Szablonowego ( TMP ), aby uniknąć powtórzeń, powinieneś go używać do tworzenia dobrze udokumentowanych, dokładnie przetestowanych abstrakcji, które lokalizują złożoność kodu TMP, ułatwiając pisanie poprawnego kodu klienta. To jest projekt standardowej biblioteki C ++.

Nie sądzę, że możemy ocenić, kto ma rację, a kto nie, nie widząc przykładu typu kodu, który próbujesz napisać.


2
Możesz także użyć funkcji kopiuj + wklej zamiast pisać ręcznie ;-)
Paŭlo Ebermann

4
@ PaŭloEbermann: Heck nie!
Joshua

2
@ PaŭloEbermann jeden sklep, w którym nazywano mnie takim podejściem, „start-mark-bug, end-mark-bug, copy-bug, copy-bug, copy-bug”.
Kelly S. French

12

Twórcy oprogramowania powinni dążyć do napisania kodu, który działa, który działa oczywiście, który może być testowany, który może być sprawdzany, który może być debugowany i który można dostosować, gdy potrzebne są zmiany. Jeśli napisanie „C z klasami” osiągnie ten cel, to będzie w porządku.

Są to standardy, według których powinieneś mierzyć swój kod. W szczególności: czy działa oczywiście, czy można go przetestować, czy można go przejrzeć, czy można go debugować i czy można go dostosować w razie potrzeby?


9

Argument ze współczucia:

Czy Twoja praca daje czas na naukę, czy alternatywnie, czy możesz przekonać swoich szefów, aby przeznaczyli kilka godzin na naukę tych funkcji językowych?

Jeśli nie, korzystanie z nich w gruncie rzeczy daje im dodatkową nieodpłatną pracę. Możesz myśleć, że programista C ++ powinien znać cały język lub coś w tym rodzaju, ale punkt akademicki nie zmniejsza obciążenia, które na nich nałożysz. Twoi koledzy mają dzieci, chorych rodziców, chorych małżonków - lub piekło, po prostu rozsądne życie towarzyskie, które nie wymaga nauki języka C ++. Bardziej głosowy przeciwnik twojej propozycji może być leniwy - lub może przechodzić ciężki okres i nie potrzebuje teraz dodatkowego gówna w swoim życiu.


8

Kod powinien być napisany najpierw dla ludzi do czytania, a tylko przypadkowo dla kompilatora do parsowania.

Teraz, o czym należy pamiętać w przypadku trywialnych TMP, należy ograniczyć liczbę osób, które potrafią odczytać ten kod. Może to być ważny kompromis, ale argumentowałbym, że jest to znacznie bardziej rozsądny kompromis w bibliotekach i taki, w którym masz mały specjalistyczny zespół ekspertów, to jest w większej aplikacji.

Kiedy wyciągniesz wszystkie sztuczki zawarte w książce, nałożysz koszty na wszystkich innych, ponieważ muszą oni teraz zrozumieć język, w tym wszystkie sprawy prawne, które wykorzystałeś, a także nałożyć koszty na zatrudnienie, ponieważ podniosłeś poprzeczkę pracować nad aplikacją w przydatny sposób, teraz może warto, ale uważaj na koszty ...

Dla mnie trochę więcej pisania, może nawet trochę duplikacji kodu, ale to, co mogę wprowadzić przed panem „C z klasami plus STL”, gdy wymaga modyfikacji, jest o wiele bardziej przydatne niż jakaś niezwykle elegancka rzecz TMP, którą tylko ja mogę utrzymać (I dlatego będzie na zawsze utrzymywać). Pamiętaj również, że facet C z klasami może być ekspertem w tej dziedzinie, a wiedza ta jest zwykle o wiele cenniejsza niż bycie prawnikiem językowym.

Zapominam, kto to powiedział, ale „Wszyscy wiedzą, że debugowanie jest trudniejsze niż pisanie go w pierwszej kolejności, więc jeśli programujesz go tak sprytnie, jak tylko potrafisz, to jak to debugujesz?”.

Nawet jeśli potrafię pisać naprawdę nowoczesne C ++, zwykle wolę tego nie robić, oznacza to, że muszę mniej programować.


7

Nie, nie powinieneś. Jesteś zatrudniony do tworzenia kodu, który spełnia specyfikację. Ten kod musi być łatwy do utrzymania, a nie podróż ego. Jutro możesz zostać potrącony przez autobus, więc ktoś musi odebrać kod i wykonać zadanie. Pozytywne jest jednak przekonanie pracodawców do włączenia nowych technik do standardów programowania.


3
Jesteś zatrudniony do tworzenia kodu, który spełnia specyfikację. tak, ale zapominacie o tym również według najlepszej wiedzy .
t3chb0t

2

Jedynym sposobem odpowiedzi na to pytanie w kontekście jest przyjrzenie się konkretnym problemom i konkretnemu sposobowi ich rozwiązania za pomocą meta programowania. O ile nie podasz tutaj kodu, nie możemy wiedzieć, czy pozwoliłeś sobie na niepotrzebną komplikację, która sama jest dla ciebie przyjemnością, „rozwiązując” nieistniejący problem; lub czy wykorzystałeś pełną moc języka, aby napisać proste, eleganckie rozwiązanie niedostępne w inny sposób.

Jeśli tak, zachęcam do kontynuowania tego wraz ze swoim zespołem.Każdy dobry zespół musi dokonać sensownych recenzji kodu, które omawiają nie tylko problemy ze stylem, ale także to, czy rozwiązanie programisty stosuje najlepsze podejście, używa odpowiednich funkcji językowych, jest możliwe do utrzymania i testowania itp. Twoje meta programowanie powinno wypełnić jedną taką sesję przeglądu, prawdopodobnie całe popołudnie. Programiści, którzy odrzucają twoje podejście, powinni przedstawić alternatywne rozwiązania (takie jak generowanie kodu z perlem, powielanie kodu itp.) I pokazać, jak radzi sobie z wymienionymi kryteriami, w porównaniu do twojego rozwiązania. Twoim zadaniem, jako ich przyjaznym „przeciwnikiem” w argumencie, jest pokazanie, że jest to sposób na szybkie wykonanie zadania, że ​​konserwacja jest łatwa, testowanie jest łatwe, a kod jest w rzeczywistości czytelny, gdy przejdziesz przez przeszkodę analizując zabawną gramatykę.

Większość programistów jest leniwa i lubi eleganckie, małe rozwiązania. Jeśli twoje jest jedno, są szanse, że uda ci się je przekonać, szczególnie jeśli pokazane alternatywy nie będą wystarczające.


0

Nie ma jednej poprawnej odpowiedzi na to pytanie.

Ponieważ pierwszą rzeczą, którą powinieneś sobie zadać, jest to: w jakiej sytuacji jesteś zatrudniony? Niektóre osoby są rzeczywiście zatrudnione jako małpy kodowe do kodowania specyfikacji, inne są zatrudnione jako gracze zespołowi, inne są pracownikami wiedzy lub ekspertami.

Jedyną stałą kwestią jest to, że musisz spojrzeć na to z perspektywy swojego pracodawcy, ponieważ w gruncie rzeczy oznacza to bycie pracownikiem. Czasami w najlepszym interesie twojego pracodawcy leży skłonienie współpracowników do poprawy i opanowania zaawansowanych technik. Jednak w innej sytuacji możesz po prostu stworzyć wiele problemów i zobowiązań i zagrozić powodzeniu projektów, w które jesteś zaangażowany.


-4

Pytanie tak naprawdę nie dotyczy tego, czy meta-programowanie jest w porządku, ale raczej, czy lepiej jest być lepszym niż inni w zespole, więc oto kilka kontrowersyjnych punktów na temat tego, jak to widzę ...


Niedawno przeniosłem się do nowej pracy, w której pracuję w większym zespole, a to [metaprogramowanie] martwi niektórych moich kolegów, ponieważ oni tego nie rozumieją.

Martwią się, że jesteś lepszy od nich. Dobre. Będziesz nowym ekspertem. Właśnie zniszczyłeś ich status quo.


Zawsze staram się wykorzystać pełny potencjał języka, ale niektórzy (nie wszyscy) moi koledzy postrzegają to jako ryzyko (niektórzy z zadowoleniem przyjmują takie podejście).

Jasne, nikt nie lubi być mniej wykwalifikowany niż ktokolwiek inny, dlatego starają się powstrzymać cię przed użyciem zbyt skomplikowanych technik. Albo nie mogą tego zrozumieć, albo nie zamierzają, ponieważ czują się teraz bezpiecznie.


Zgadzam się, że pisanie kodu jest problemem, którego nikt inny w zespole nie jest w stanie zrozumieć.

Ja nie. Myślę, że to pokazuje twoją wiedzę.


Moje pytanie brzmi: kto ma rację, co powinienem zrobić?

Powinieneś wykorzystać wszystkie swoje umiejętności, aby napisać najlepszy kod, jaki możesz napisać i nie spoglądać za tych, którzy go nie rozumieją. W przeciwnym razie utkniesz na ich poziomie i będziesz zwykłym programistą. Dobrze jest być lepszym od innych i dobrze jest dążyć do bycia lepszym od nich. Nigdy nie zyskasz żadnego nowego doświadczenia, jeśli nie spróbujesz użyć niczego nowego lub nie zrobisz czegoś inaczej.


Wiem, że zostanę przegłosowany, ale tak to wygląda. Bycie lepszym od innych w zespole nie jest przestępstwem i wykorzystywanie swoich umiejętności nie jest przestępstwem. Po prostu wszyscy boją się to przyznać ... ponieważ są po stronie niewykwalifikowanej i nienawidzą tego, że nowy facet nagle może zrobić coś, czego nie może. Gdyby byli sprytni, poprosiliby cię o pomoc i radę i nie krytykowali twojego kodu za niezrozumienie.


EDYTOWAĆ

Wydaje się, że istnieje wiele zamieszania w związku z tym pytaniem. Komentarze pokazują, że wiele osób uważa, że ​​chodzi o ogólną czytelność kodu. Nie, nie jest. Chodzi o to, czy niektóre funkcje / konstrukcje językowe powinny być zabronione czy unikane, ponieważ niektórzy członkowie zespołu ich nie rozumieją.

Moja odpowiedź brzmi: nie . Nie powinny być zabronione. Jeśli chcesz coś zabronić, jak byś to zrobił? Będziesz musiał przygotować jakiś kwestionariusz, aby dowiedzieć się, co członkowie twojego zespołu mogą, a czego nie mogą - a raczej nie chcą się uczyć, ponieważ uważam, że wszystkie funkcje języka są gdzieś przydatne, więc ich znajomość i możliwość korzystania z nich jest zawsze dobrze, a im więcej wiesz, tym lepszy kod możesz napisać. Potrzebujesz również skali, aby określić, które funkcje są dla początkujących, średnio zaawansowanych lub zaawansowanych.

Aby pokazać, jak głupie są takie ograniczenia, weźmy naprawdę prosty przykład: będziesz zatrudniony jako inżynier oprogramowania, ale twój przyszły szef mówi ci, że nie będziesz mógł używać do/whilepętli, ponieważ jest kilka osób na zespół, który nigdy wcześniej ich nie używał, a także tego nie zrobi, ponieważ zawsze używali forpętli do wszystkiego, więc uważają do/whilepętle za mylące.

Teraz myślisz, że to głupie i szalone, prawda? Ale tak samo zabrania się innych funkcji. Niektórzy ludzie mogą z nich korzystać, a inni nie chcą się ich uczyć.

Dlaczego powinieneś produkować gorszy kod, jeśli wiesz, że jest coś, co pozwala ci robić to samo przy znacznie mniejszym wysiłku, a jednocześnie zapewnia o wiele bardziej czytelny, solidny kod?

I nie ma znaczenia, czy używasz tylko podstawowych funkcji językowych, czy zaawansowanych, możesz użyć jednego z nich, aby stworzyć równie nieprzenikniony i niemożliwy do utrzymania kod, więc jest to zupełnie inny temat.


10
Ta odpowiedź jest okropna.
Metaprogramowanie

9
Z mojego doświadczenia wynika, że ​​każdy, kto uważa, że ​​ma znacznie wyższy poziom wiedzy niż reszta zespołu, faktycznie padł ofiarą efektu Dunninga-Krugera. Nie oznacza to, że niektórzy ludzie nie są dużo bardziej wykwalifikowani niż inni, lub że w tym przypadku reszta zespołu nie jest w rzeczywistości niekompetentna ... ale prawdziwy ekspert zawsze koncentruje się na prostym kodzie i dużym obrazie inżynieria (w tym uwzględnianie efektów zespołu w czasie), a nie tylko programowanie punktów stylu.
Daniel Pryden,

3
Pisanie kodu, którego inni nie potrafią odczytać, nie dowodzi, że jesteś od nich lepszy. To dowodzi, że nie możesz napisać czytelnego kodu.
Stig Hemmer

3
@StigHemmer najwyraźniej nie rozumiesz pytania i zmieniasz temat. Nie chodzi o nieczytelny kod, ale o kod niezrozumiały dla innych z powodu braku wiedzy.
t3chb0t

4
@ t3chb0t Chodzi mi o to, że te dwa są tym samym.
Stig Hemmer
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.