Jak zachęcić kolegę, by pisał czyste funkcje?

0

Hej.

Piszę w pythonie. Mam w projekcie mniej doświadczonego kolegę, który pisze nieczyste funkcje.
Chcę go przekonać, by to zmienił. Mam jednak problem, bo całą moją argumentację można by zawrzeć w kilku zdaniach:

"Ziom! Kod jest wtedy elegancki. Zanim zacząłem tak pisać, miałem mnóstwo problemów.
Niestety, nie pamietam już, co to były za problemy. Teraz po prostu ich nie ma, bro!"

Na 90% taka argumentacja go nie przekona.

Ważne! Nie szukam argumentacji logicznej. Z moich obserwacji wynika, że logika rzadko kiedy kogoś do czegoś przekonuje.
Szukam za to inspiracji. Np. jakiegoś nagrania na YT, gdzie ktoś podaje zajebiste przykłady i mówi o czystych funkcjach z pasją w oczach.

Ma ktoś może jakiś pomysł?

[EDIT] Albo inaczej. Co Was przekonało do pisania czystych funkcji?

5
  • Łatwiejsze czytanie kodu: tylko input i output się liczy
  • Mniejsza szansa na zepsucie czegoś
  • Testy są banalne tj. assert foo(x) == y
  • można łatwo cachować jak jest taka potrzeba
  • kod jest łatwy do przeniesienia gdzieś indziej: trzeba tylko przenieść tą funkcję i funkcje wołane przez nią
  • nie trzeba myśleć o concurrency
2

Powiedz że kod będzie non-Pythonic ;)

8

Dlaczego chcesz go przekonać?

1

Ale python generalnie z tego co wiem średnio pasuja czyste funkcje do Pythona. Python nie wspiera efektywnie niemutowalnych kolekcji, jest sterowanie logiki przez wyjątki itp.

0

A możesz napisać, o jakiego rodzaju nieczystości chodzi?

1

W zależności jakie to nieczystości, ale ciągłe komentarze na code review. Ustalacie standard i się go trzymajcie :)

3
dedicated napisał(a):

[EDIT] Albo inaczej. Co Was przekonało do pisania czystych funkcji?

To że od globalnego/zmiennego stanu mieszało mi się w głowie

S4t napisał(a):

A możesz napisać, o jakiego rodzaju nieczystości chodzi?

Ja obstawiam że chodzi o pisanie Pure function:

In computer programming, a pure function is a function that has the following properties:[1][2]

  • the function return values are identical for identical arguments (no variation with local static variables, non-local variables, mutable reference arguments or input streams), and
  • the function application has no side effects (no mutation of local static variables, non-local variables, mutable reference arguments or input/output streams).

Thus a pure function is a computational analogue of a mathematical function. Some authors, particularly from the imperative language community, use the term "pure" for all functions that just have the above property 2[3][4] (discussed below).

1

Stwierdzenie, że ktoś piszę "nie czysto" jest IMO bardzo generalnym stwierdzeniem.

1
dedicated napisał(a):

[EDIT] Albo inaczej. Co Was przekonało do pisania czystych funkcji?

W krótkiej perspektywie - testowanie, w dłuższej - utrzymywanie projektu.

2
Silv napisał(a):

Dlaczego chcesz go przekonać?

Rzeczywiście dobre pytanie. Zdałem sobie dzięki niemu sprawę, że piszę czysto, ponieważ ... jest mniej niespodzianek.

0

@dedicated: Zadałem takie pytanie, ale to niekoniecznie oznacza, że chcę lub nie chcę, byś go przekonywał. Problem postawiłbym raczej taki, że Twoje własne doświadczenia z kodem niekoniecznie muszą odpowiadać doświadczeniom kolegi. Być może on potrzebuje jeszcze nauczyć się (na błędach), jakie zalety mają czyste funkcje? A być może akurat jemu łatwiej pisać kod, w którym nie są czyste funkcje?

Ja uważam, że tak, czyste funkcje są lepsze od tych niebędących czystymi. Ale to jest moje zdanie na podstawie moich przemyśleń. Nie znam Pythona i nie wiem, jak łatwo w nim pisać czyste funkcje. Poza tym pamiętam, że dawniej… w ogóle mnie nie obchodziło, czy coś jest czystą funkcją, czy nie, bo miałem problemy z innymi aspektami programowania. Ważniejsze było, by kod w ogóle działał, i był skończony w skończonym czasie…

1

Pisanie czystych funkcji nie jest wcale koniecznością. Owszem, zdarza się że rozwiązania na nich bazujące wyglądają elegancko, ale to kwestia gustu.

5

Powiedz mu że biblia nakazuje utrzymanie czystości aż do ślubu.

dedicated napisał(a):

"Ziom! Kod jest wtedy elegancki. Zanim zacząłem tak pisać, miałem mnóstwo problemów.
Niestety, nie pamietam już, co to były za problemy. Teraz po prostu ich nie ma, bro!"

No to wytknij mu przy najbliższym znalezionym bugu w jego kodzie, pokaż mu że czyste funkcje by przed tym ochroniły, o ile to prawda. Jeśli nie znajdzie się żaden problem to nie ma problemu.

To brzmi trochę śmiesznie - bardzo wielu programistów powiela wzorce i schematy które widzieli w poprzednich projektach lub gdzieś o nich przeczytali a nie do końca rozumieją co one dają. Czasem je przenoszą z języka do języka i stosują mimo że w danym języku nie mają sensu, dorabiają sobie pracy z której nie ma żadnej korzyści. Nie wciskaj innym rozwiązań których samemu do końca nie wiesz po co stosujesz

Czyste funkcje są fajne ale stosowanie ich wszędzie uważam za fanatyzm, czasem coś po prostu jest maszyną stanową i dużo łatwiej, szybciej i czytelniej to zrobić "nieczysto"

1

Opie***ol go przy wszystkich. Albo zacznij podrzucać mu arty o czystym kodzie.

1

A ten kolega to w ogóle programista jest? :) Bo jak on pisze większość (czasem nieczystą trzeba napisać, no ale to tak z 1%) funkcji nieczystych, to jak on to potem utrzymuje?

5
dedicated napisał(a):

[EDIT] Albo inaczej. Co Was przekonało do pisania czystych funkcji?

Długa praca z czystmi i nie czystymi, przez lata, i powolne dostrzeganie że z jednymi się pracuje fajnie, z innymi gorzej. Sam zgadnij z którymi :>

Owszem, możesz używać argumentów żeby opowiedzieć się za jednym bądź drugim, ale one rzadko są ostateczne, zawsze znajdą się powody żeby zrobić nie pure funkcje, taka ocena wynika tylko z lat doświadczenia programistycznego.

6
dedicated napisał(a):

[EDIT] Albo inaczej. Co Was przekonało do pisania czystych funkcji?

Wszystko sprowadza się do tego, czy potrafisz udowodnić, jak wygląda wejście dla funkcji, bo to pozwala na dowodzenie bądź obalanie hipotez i prostsze wnioskowanie o działaniu kodu. Czyste funkcje mają małe pole rażenia, bo zależą tylko od parametrów na wejściu, bo czysta funkcja ma wejście I (input) oraz wyjście O (output). Funkcja nieczysta ma wejście (I, S), gdzie S to stan aplikacji, potencjalnie globalny, i wyjście O. Obie funkcje dają zawsze takie samo wyjście dla tego samego wejścia, ale różnica jest w tym, że dla czystej funkcji wejściem jest jedynie I, a dla funkcji nieczystej jest to (I, S).

Teraz pytanie, co ten S właściwie zmienia? Można go przecież traktować, jako niejawnie przekazywany parametr "stan aplikacji" czy coś w tym rodzaju i z tego punktu widzenia wszystkie funkcje są czyste, bo prostu te "czyste czyste" przyjmują (I, zbiór pusty), a te "nieczyste czyste" przyjmują (I, S). Ale to zmienia bardzo dużo, bo o ile dla ustalenia I (czyli udowodnienia jakichś hipotez lub założeń) potrzebujemy zazwyczaj przeanalizować jedynie miejsce wywołania funkcji, o tyle ustalenie S jest potencjalnie o wiele trudniejsze. A to z tego względu, że o I możemy wnioskować liniowo, czyli najpierw w miejscu wywołania funkcji, potem w miejscu wywołania poprzedniej funkcji i tak dalej, przez cały stos wykonania, ale nie możemy tego samego zrobić z S, bo ten może być zmieniony zarówno przez obecną funkcję, jak i przez całą poprzednią historię wykonania. Mówiąc prościej: żeby udowodnić, że I jest takie i takie, wystarczy zazwyczaj pokazać, jak to I zostało ustawione (czyli wystarczy "przykład na dowód tezy"). Ale żeby udowodnić, że S jest takie i takie, to zazwyczaj muszę nie tylko pokazać, jak S zostało ustawione, ale też wykazać, że żadne miejsce w kodzie mi tego S nie zmieniło - czyli muszę pokazać, że nie istnieje żaden kontrargument. To może być o wiele trudniejsze, bo muszę przeanalizować o wiele więcej kodu (bo wiele funkcji ma dostęp do tego samego stanu), bo mogę nie wiedzieć, jak S jest zmieniane (czy "po ludzku", czy refleksją, czy hakami na pamięci), bo mogę nawet nie mieć dostępu do całego kodu, żeby to udowodnić (bo na przykład stan jest modyfikowany przez dynamicznie ładowaną wtyczkę, której nie posiadam).

Jeżeli potrafię trzymać w ryzach rozmiary I oraz S, to cała reszta jest już kwestią gustu i nie ma mierzalnej przewagi funkcji czystej nad nieczystą. Odpowiadając na Twoje pytanie — nie jestem przekonany do pisania tylko czystych funkcji, ale jestem przekonany, że wolę tak limitować I oraz S, żeby móc łatwo o funkcji wnioskować. Tu oczywiście do gry wchodzą umiejętności kognitywistyczne, doświadczenie i biegłość w programowaniu — dla jednej funkcji (i jednego programisty) trzy parametry wejściowe będą zbrodnią, dla innej funkcji (lub innego programisty) pięć zmiennych globalnych nie będzie żadnym problemem.

Dygresja: tak właściwie, to wszystkie funkcje przyjmują jeszcze parametr E, czyli środowisko wykonywania, rodzaj sprzętu, wypełnienie pamięci, a nawet promieniowanie kosmiczne czy elektromagnetyczne otoczenia (które chociażby zmieniło wynik wyborów w Szwajcarii). Różnica między S a E jest taka, że S kontrolujemy wewnątrz aplikacji, a E zazwyczaj nie kontrolujemy wcale, bo o ile jeszcze możemy pośrednio wpłynąć na ilość pamięci w komputerze, o tyle zakłóceń w zasilaczu już wcale nie zmienimy, za to one mogą zmienić naszą aplikację.

0 użytkowników online, w tym zalogowanych: 0, gości: 0