Programowanie dla zaawansowanych

0

Cześć,

Programuję na froncie (TS, frameworki) od ok. 10 lat. Znam się na tym temacie trochę. Jest jeden mały problem, który dostrzegam praktycznie od zawsze, ale przez pewien czas udawało się go niwelować (bo jeszcze g* wiedziałem i myślałem, że robię postępy) - zaawansowane techniki programowania.

Trudno nawet powiedziec o co chodzi, bo w kolejnych projektach (trochę tego było) trafiam na większe lub mniejsze bagno. Z drugiej strony to co mam okazję robić od zera utrzymuje w ultra prostej konwencji - ktoś by powiedział, że pisze jak osoba, która nie zna clean code (trochę tu upraszczam).

Chodzi o to, że kod napisany wg. prawideł z książek (a nie daj boże z uzyciem wzorców) jest trochę jak znormalizowana baza - ciężkie to w refaktorze jak cholera. Trzeba obudowywac kolejnymi wzorcami, bo traktujemy to co do tej pory pwostało jako black box. I tu się zaczyna dramat osób, które jednak ten chlew musza zamienic w lśniący dom typu stodoła. Z tego powodu piszę kod w sposób maksymalnie prosty, aby moi następcy (lub ja, gdybym się zasiedział) nie dostali udaru.

No i tu pojawia się ważne pytanie: co robic, jak żyć. Jak zachowac prostotę kodu nieskażonego ideologią, ale nie wyzbywac się narzędzi typu single directional flow (jakies reduxy, ngrxy). Bo w obecnym kształcie tworza one nowotwory z przerzutami, tzn. rozwiązują jednen problem, ale dokładają takie complexity, że zabijają projekt :P Widziałem to juz wielokrotnie i mądrzy ludzie z którymi rozmawiałem o tym problemie przytakują. Przydałaby się jednak recepta (najlepiej gdyby to nie była chemioterapia).

2

Tylko że narzędzia typu single-directional flow często mają problem z enkapsulacją danych, więc jeśli uważasz że to jest dobre narzędzie, to się zastanawiam jakie masz podejście do np Dependency Inversion?

trudny-do-wymowienia napisał(a):

No i tu pojawia się ważne pytanie: co robic, jak żyć. Jak zachowac prostotę kodu nieskażonego ideologią, ale nie wyzbywac się narzędzi typu single directional flow (jakies reduxy, ngrxy). Bo w obecnym kształcie tworza one nowotwory z przerzutami, tzn. rozwiązują jednen problem, ale dokładają takie complexity, że zabijają projekt :P Widziałem to juz wielokrotnie i mądrzy ludzie z którymi rozmawiałem o tym problemie przytakują. Przydałaby się jednak recepta (najlepiej gdyby to nie była chemioterapia).

A co do tego, to większość wzorców raczej nie wynika z ideologii tylko głównie żeby rozwiązać jakiś dany problem. Większość ludzi którzy twierdzi że wzorce są po nic i zaciemniają kod najczęściej po prostu ich nie rozumieją (albo próbują je wcisnąć tam gdzie nie pasują i potem krytykują wynik).

1

(jakies reduxy, ngrxy).

Problem z Reduksem i podobnymi bibliotekami jest to, że proponują jeden globalny stan. Na tym zresztą polega ich propozycja wartości - ludzie używają ich po to, żeby mieć globalny stan zarządzany w jednym miejscu. Redux ma jako zaletę wymienione, że jest "centralized": https://redux.js.org/

I o ile ma to zalety, to praktyka pokazuje, że jak jest większa aplikacja, to ludzie i tak mają potrzebę podzielenia tego stanu na kawałki. I teraz robi się zabawa, bo najpierw wrzucamy stan do jednego kotła, a potem na siłę oddzielamy, tworzymy mniejsze reducery, które zarządzają kawałkiem stanu, setki akcji, każda do czego innego itp. Więc mamy jedną dużą aplikację z inherentnie monolitycznym stanem, który jednak podzieliliśmy na mnóstwo różnych kawałków tworząc ravioli code. I stąd wynika complexity.

Jak zachowac prostotę kodu

Myśleć bardziej modularnie i odejść od idei jednego globalnego stanu tam, gdzie go nie trzeba. Stan lokalny albo ponadlokalny (gdzie jeden komponent trzyma stan kilku pomocniczych komponentów pod sobą) często wystarcza.

Ludzie uwierzyli, że muszą mieć globalny stan, bo ktoś im tak powiedział.

Ew. są przyzwyczajeni do zmiennych globalnych i się ucieszyli, że mogą ich używać, ale w bezpieczny sposób (bo niemutowalny i reaktywny). Tylko okazało się, że w dalszym ciągu używanie stanu globalnego jest problematyczne, szczególnie jeśli robisz wszystko, żeby przykryć fakt, że jest to stan globalny, dzieląc go na kawałki, gdzie logika jest rozproszona w dziesiątkach plików.

Dość ironicznie, bo jedną z zalet Reduxa miało być to, że mając stan w jednym miejscu, możesz wszystko obserwować, debugować itp. (w porównaniu do stanu lokalnego, gdzie te dane były luzem). Tylko, że okazało się, że wcale ten stan nie jest w jednym miejscu i tak, tylko rozsiany po całej apce.

nie wyzbywac się narzędzi typu single directional flow

W jakim frameworku piszesz? W React masz to out of the box. Niepotrzebne są dodatkowe narzędzia do osiągnięcia single directional flow. Chyba, że coś innego masz na myśli.

2
Riddle napisał(a):

Większość ludzi którzy twierdzi że wzorce są po nic i zaciemniają kod najczęściej po prostu ich nie rozumieją (albo próbują je wcisnąć tam gdzie nie pasują i potem krytykują wynik).

Lub są im narzucane formalnie / mentalnie, czy jako nakaz / usilne zalecenie firmowe w stylu "best pracitce". Gdzieś zasłyszane "musisz użyć trzech wzorców"

Ja lubię o wzorcach mówić z "o kurcze"
Od lat ludzie rozwiazują podobny problem i zbiorowo odkryliśmy "o kurcze, rozwiazujemy to podobnie, nazwijmy to 'observer' 'strategy' 'whatever'

@trudny-do-wymowienia: Nie czuj się zmuszony do użycia szerokiego spektrum wzorców (mniej tylko smieszą święte wojny o ilośc wzorców, czy jest ich np dokładnie 21 - to doskonałe zaprzeczenie "o kurcze") , użyj tych które ci leżą.
Mam przypuszczenie, że wielokrotnie ich użyłeś, tylko nie wiedziałes że tak sie nazywają. Sam pamietam u mało roziwinętego internetu wielokrotnie z dobrym skutkiem uzywałem czegoś, co potem dowiedziałem nazywa się strategią. Myśalłem o tym już nie pamiętam jak ... moze jako "wtyczka" czy "wymienna funkcjonalność"

ps.obok w wątku kol nie używa klas, bo podobno zmuszają do zaciemniająco duzej ilosći słów kluczowych ....

4

Od lat ludzie rozwiazują podobny problem i zbiorowo odkryliśmy "o kurcze, rozwiazujemy to podobnie, nazwijmy to 'observer' 'strategy' 'whatever'

Ale z drugiej strony - ma to wielki plus. Bo potem, jak gadasz z kolegą z zespołu to nie musisz tłumaczyć od zera w stylu zrób klasę, która będzie dziedziczyć z takiego interface, tam tworzymy powiązanie z kolekcją, która będzie generować obiekty podłączane w kolejce i nasłuchujące wiadomości od obiektu nadrzędnego, który kontroluje komunikacje i cykl życia blablablalbla..... tylko rzucasz zrobimy to w oparciu o fabrykę abstrakcyjną i do tego dorzucimy fasadę i obserwatora. i od razu wiadomo o co chodzi. Tak samo, jak lekarze - posługują się fachowymi określeniami narządów, a nie to duże coś po lewej stronie brzucha z 2 tętnicami, co odpowiada za rozkład cukrów :P

Ale poza tym to pełna zgoda - wzorce to nie jest żadna tajemna wiedza, tylko po prostu oficjalnie nazwane i skatalogowane często stosowane przypadki. Sam jak sobie w zeszłym tysiącleciu pisałem różne aplikacje, to stosowałem różne mechanizmy. Wtedy nie miałem pojęcia, że coś takiego jak wzorce istnieją. Potem usłyszałem o wzorcach i z lekkim przestraszeniem zacząłem o nich czytać. To miało być coś super-profesjonalnego, skomplikowanego i ogólnie - podchodziłem z szacunkiem i rezerwą. A okazało się, że tak, jak napisałeś - wiele z nich sam wymyśliłem i intuicyjnie wykorzystywałem. Także - wzorce nie są czymś niesamowitym, ale jest jakiś dziwny ich kult. I podejście, że trzeba dać 3-4 bo inaczej projekt jest amatorski/nieprofesjonalny.

4

To ja powiem od jeszcze innej strony. To co kiedyś usłyszałem od jedego forumowicza tutaj. Idea wzorca programowania oznacza że język nie daje rady. Bo najlepiej by było jakby wszystko dało się zakodować jakimś generycznym kodem i wrzucić do biblioteki. A język programowania nie daje rady i wtedy mamy wzorzec programistyczny czyni szablon kodu który za każdym razem trzeba powtórzyć. Takie spojrzenie daje nadzieję na to że im lepsze są języki programowania tym więcej wzorców umrze. Taki np wzorzec Singleton nie ma racji bytu w Scali czy Kotlinie, bo singleton jest wbudowany w język. A wzorzec strategia w wielu językach może być zastąpiony lambdami. Bo lambdy dają już ustandaryzowany "interfejs" i nie ma sensu tworzyć własnego jak lambdy są wystarczające

Kiedyś oglądałem prezentację gdzie człowiek przekonywał że nawet funkcja z parametrami to wzorzec projektowy w prymitywnych językach jak Assembler (lub stare Basici). No bo przy każdym wywołaniu funkcji musisz zrobić ileś kodu szablonowego jak np odłożenie parametrów na stos

BTW właśnie sobie zdałem sprawę że monada w Javie też jest wzorcem programistycznym. Podczas gdy w językach które mają HKT można ją zakodzić jako szeroko rozumiany "interfejs" i umieścić w bibliotece jak w Haskellu

2

@KamilAdam:

No tak ... w jakims sensie tak.
Ale żeby w nowoczesnym języku użyć lambdy, trzeba posiadac (i musieli go posiadać projektanci języka) ... trzeba posiadać intelektualny wzorzec wyniesienia funkcjonalności z kontraktem na zewnątrz, wzorzec (np) strategii.
Lub wzorzec ... np obserwatora - króty jest odmienny wzorcem, choć też lambdą da się zakodowac ....

Więc tak, nie ma już (w nowoczesnym języku) new XxxxxStrategy ale jest to samo myślenie wzorcem.
Choć trochę żal klepać nienazwaną lambdę (kto w przyszłości zgadnie intencje autora) w/s new NaliczeniePPkStrategy() ... czy to zawsze postęp ??

0
ZrobieDobrze napisał(a):

Ale żeby w nowoczesnym języku użyć lambdy, trzeba posiadac (i musieli go posiadać projektanci języka) ... trzeba posiadać intelektualny wzorzec wyniesienia funkcjonalności na zewnątrz, wzorzec (np) strategii

Nie wiem, mi zawsze było nie podrodze z OOP. BTW pierwszy raz "strategię" a wzasadzie przekazanie funkcji przez parametr użyłem w Pascalu XD

Więc tak, nie ma już (w nowoczesnym języku) new XxxxxStrategy ale jest to samo myślenie wzorcem.
Choć trochę żal klepać nienazwaną lambdę (kto w przyszłości zgadnie intencje autora) w/s new NaliczeniePPkStrategy() ... czy to zawsze postęp ??

W językach obiektowych gdzie lambdy często lambdy są interfejsami możesz zrobić sobie dziedziczenie. Np w Scali:

class NaliczeniePPkStrategy extends Function1[MyParam, MyResult]

Albo jak język wspiera aliasy dla typów (jak Kotlin, Scala Haskell) to:

type NaliczeniePPkStrategy = Function1[MyParam, MyResult]

I wtedy parametr będziesz miał typu NaliczeniePPkStrategy (w celach dokumentacyjnych), ale dalej będzie to zwykła lambda

3

@KamilAdam:

Nie ... no OK.
Ale DLA MNIE we wzorcach nie kodowanie jest najważniejsze, a myślenie.
Chrzanić kod, wazne jest uniknąć drabinki if'ów - przez wyniesienie.

Jak mam spójne "myslenie o problemie", to w C czy w Groovym *) wyniosę na zewnątrz - choć będzie to totalnie inaczej zakodowane.

*) ostatnio mi blisko, traity te sprawy ...

1

Przypomniało mi się niepowodzenie w edukacji / promowaniu konkretnie Strategii.
Gości pozyskiwał ze strategii string (z typem dokumentu czy coś w tym stylu), i w kodzie głównym jechał if'ami if(typdokuemntu == "xxx")

Nie dał sobie przestawić w głowie - ale to był Jego Wysokosć Zasłużony Borlandowiec, trudno spodziewać się więcej.

4
cerrato napisał(a):

Także - wzorce nie są czymś niesamowitym, ale jest jakiś dziwny ich kult. I podejście, że trzeba dać 3-4 bo inaczej projekt jest amatorski/nieprofesjonalny.

To nie jest kult lecz antykult - z jednej strony lęk, z drugiej ludzie zakuwają jakieś definicje przed rozmową kwalifikacyjną, a potem w pracy nie są w stanie w żaden sposób sensownie nie podzielą kodu ani nie uczynią go elastycznym, bo zwyczajnie nie są w stanie go dostrzec w praktyce.
Tak jak składnia języka jest alfabetem, tak stosowanie wzorców projektowych jest umiejętnością budowania zdań.

ZrobieDobrze napisał(a):

Ale DLA MNIE we wzorcach nie kodowanie jest najważniejsze, a myślenie.
Chrzanić kod, wazne jest uniknąć drabinki if'ów - przez wyniesienie.

Ja już tu kiedyś próbowałem wytłumaczyć, że wzorzec definiuje się przez cały kontekst - problem, rozwiązanie i konsekwencje użycia. No ale szkoda strzępić ryja, niektórzy nie są w stanie wyjść poza poziom składni języka, więc dla nich wzorce to tylko jakieś tam połączone ze sobą interfejsy.

0
somekind napisał(a):

To nie jest kult lecz antykult - z jednej strony lęk, z drugiej ludzie zakuwają jakieś definicje przed rozmową kwalifikacyjną, a potem w pracy nie są w stanie w żaden sposób sensownie nie podzielą kodu ani nie uczynią go elastycznym, bo zwyczajnie nie są w stanie go dostrzec w praktyce.
Tak jak składnia języka jest alfabetem, tak stosowanie wzorców projektowych jest umiejętnością budowania zdań.

Tak jest w istocie - ale chciałbym tylko zauważyć że ponieważ języki oprogramowania to w zasadzie pomosty między kodem maszynowym a językami ludzkimi to poprzez analogię możemy powiedzieć że wzorce projektowe to zasady retoryczne dla języków w gruncie rzeczy martwych (albo klasycznych).

W codziennej praktyce mało kto się nimi przejmuje bo dominuje odmiana potoczna (język żywy) którego głównym celem jest przekazanie informacji w kontekście szybko zmieniającej rzeczywistości.

2
loza_prowizoryczna napisał(a):

W codziennej praktyce mało kto się nimi przejmuje bo dominuje odmiana potoczna (język żywy) którego głównym celem jest przekazanie informacji w kontekście szybko zmieniającej rzeczywistości.

Czyli nawijanie makaronu na uszy?

0
somekind napisał(a):

Czyli nawijanie makaronu na uszy?

Osobiście wolę jeśli coś działa to nie jest głupie, może co najwyżej być niepodobne.

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