2016-07-21 14 views
7

Czytałem i bawiłem się programowaniem funkcjonalnym (FP) i bardzo lubię jego koncepcje, ale nie jestem pewien, jak zastosować je w przypadku większości moich aplikacji.Jak korzystać z programowania funkcjonalnego przy projektowaniu aplikacji

Będę bardziej szczegółowy, porozmawiajmy o aplikacjach na iOS. Widzę, jak wykorzystać niektóre z koncepcji, takie jak niezmienne struktury danych i funkcje wyższego rzędu, ale nie jak pracować z tylko/głównie czystymi funkcjami - unikając efektów ubocznych - które wydają się być główną częścią FP.

Czuję, że większość aplikacji dotyczy koordynacji wywołań wejściowych, wyświetlania danych, zapisywania danych, wysyłania żądań sieciowych, nawigacji między ekranami, animacji.

Wszyscy byłoby funkcje nieczyste na FP:

  • koordynująca wejściowe: kranu przycisku, powiadomienie, push gniazdo serwera, dla tych wszystkich, muszę zdecydować, co nazywamy, gdzie je obserwować, itp.
  • Wyświetlanie danych: odczyt z lokalnej bazy danych lub z serwera (efekt uboczny).
  • Zapisywanie danych: tak samo jak powyżej (ale pisanie).
  • Tworzenie żądań sieciowych: oczywiste, więc podam tylko przykład - pobieranie listy obrazów z Instagrama.
  • Nawigacja: to zasadniczo przedstawienie kontrolerów widoku, które są efektem ubocznym.
  • Animacje: zmiana czegoś na ekranie, efekt uboczny.

Istnieje bardzo niewiele miejsc, w których mam do przetwarzania danych, a te składają się prawie zawsze z pobierania niektórych Struct z bazy danych i łączenie się z wieloma informacjami na inny Struct, który będzie używany przez View Controller (to jak 5 linie ... zakładając, że potrzebujesz 5 właściwości do wyświetlenia w widoku). Oczywiście, może być konieczne wykonanie przetwarzania, takiego jak konwersja money: Int = 20 to moneyString: String = "US$\(money).00", ale to wszystko.

Czuję, że nie wdrażam DF w moim cyklu rozwoju aplikacji. Czy ktoś może wyjaśnić, w jaki sposób mogę to osiągnąć? Może z przykładami.

Dziękuję.

EDIT: teraz, po Clean Architecture pomysł, mam coś takiego jak mój architektury:

enter image description here

Wejścia mogą pochodzić z View, jak kliknięcie przycisku, idą do ViewController, który decyduje, który Interactor zadzwonić. Ten Interactor uzyska dostęp do niezbędnych Gateway s, aby uzyskać pewne dane i przekształcić je w reprezentatywne dane, które zostaną przekazane do Presenter (w formie delegata). Wreszcie Presenter zaktualizuje View, aby wyświetlić nowe dane.

Dodatkowo dane wejściowe mogą pochodzić ze źródeł External, takich jak serwer z informacją, że niektóre dane zostały zaktualizowane i trzeba odświeżyć numer View. To trafia do Interactor (w postaci obserwatora), który będzie podążał za resztą łańcucha, tak jak w poprzednim przykładzie.

Jedyną częścią FP jest przekształcenie danych Gateway w prezentowalne dane.Cała reszta ma efekty uboczne. Czuję, że robię coś złego i być może część tego kodu powinna być zorganizowana inaczej, aby więcej kodu mogło zostać przeniesione do czystych funkcji.

+0

@Sami Kuhmonen Zaktualizowałem moje pytanie, aby było bardziej szczegółowe. –

+0

@ Paulw11 Zaktualizowałem moje pytanie, aby było bardziej szczegółowe. –

+0

@dfri Zaktualizowałem moje pytanie, aby było bardziej szczegółowe. –

Odpowiedz

0

W zestawie narzędzi zawsze powinno znajdować się więcej niż jedno narzędzie. FP to świetne podejście i dyscyplina, którą większość ludzi powinna mieć dla fragmentów programu, w których ma on zastosowanie (np. Prezentowanie modelu na widokach za pomocą kontrolerów widoku w MVVC).

Próba użycia FP na wszystkich elementach aplikacji prawdopodobnie nie jest wartym wysiłku. Jak tylko będziesz utrzymywał dane lub zarządzał upływem czasu, będziesz musiał radzić sobie z państwami. Nawet "spokojne" usługi (które są koncepcyjnie dobrymi kandydatami do podejścia opartego na zasadach PR) nie będą czystym PR i będą uzależnione od państwa. Nie dzieje się tak dlatego, że są one złymi implementacjami PR, ale dlatego, że ich celem jest zarządzanie stanami utrzymującymi się z zewnątrz. Można go obrócić, aby wyświetlić zapisane dane jako "dane wejściowe", ale z dowolnej strony usługi druga strona nadal będzie efektem ubocznym (z wyjątkiem operacji tylko do odczytu).

Jeśli wymyślisz fakt, że MVVC jest odpowiedzialna za zarządzanie przejściem stanu i pozwala na związek pomiędzy jego komponentami, łatwiej jest wprowadzić paradygmat FP w mniejszej skali do każdego z nich.

Na przykład kontrolery widoku nie powinny zawierać żadnych zmiennych, które powielają lub zachowują przekształcone wersje jakichkolwiek danych w modelu. Użycie delegatów między komponentami MVVC w niektórych przypadkach narusza zasady FP, ale w zakresie funkcjonalności kontrolera widoku są to dane wejściowe (a nie stany). Planując (i rysując) diagram interakcji przed rozpoczęciem kodowania, będziesz w stanie lepiej izolować obawy i nie wchodzić w ślepe zaułki, które złamią FP w obrębie twoich komponentów.

W samym modelu obliczone właściwości mogą w dużym stopniu przyczynić się do przestrzegania FP.

W każdym razie, jeśli nigdy nie użyjesz instrukcji var (to będzie wyzwaniem w niektórych miejscach), prawdopodobnie skończy się to na kodzie zgodnym z FP.

+0

Jak mogę usunąć powielone przekształcone dane w UITableViewController? Potrzebuję tablicy tam do wykorzystania w moich metodach źródła danych. –

+0

Zaktualizowałem moje pytanie, aby dodać bardziej konkretny przykład mojej architektury. –

0

Programowanie funkcjonalne sprawdza się w rozwiązywaniu konkretnych problemów programistycznych. Gdzie Excel przoduje w programowaniu równoległym/równoległym; jeśli przeczytałeś któryś z artykułów napisanych przez Herb Sutter na temat programowania współbieżnego, zaczynasz dostrzegać nakładanie się dobrych programów współbieżnych/równoległych i projektowania funkcjonalnego.

Na wniosek, jak powiedział Alain, trzeba pracować z państwem. Możesz zastosować schematy projektowe FP w zależności od tego, jak modyfikowany jest stan, ale niezależnie od tego, musisz zmodyfikować stan w tym czy innym punkcie, który, jak odkryłeś, nie jest zgodny z czystym FP.

FP to narzędzie w skrzynce narzędziowej do programowania wzorów, ale nie jest to jedyne narzędzie.

+1

Mam ok stan w mojej warstwy widoku (Widoki i ViewControllers), ale wydaje się, że większość mojej aplikacji jest po prostu przekazywanie informacji wokół, więc mój problem jest z efektami ubocznymi, jak w czytaniu z bazy danych. Czy nie dzielę części kodu, który nie powinien iść w tym samym miejscu co mój ViewController? –

+0

Zaktualizowałem moje pytanie, aby dodać bardziej konkretny przykład mojej architektury. –

2

Odkładając na bok PR na chwilę, wyzwaniem dla modeli wielodostępnych lub zależnych od czasu jest to, że użytkownik końcowy przed programem nie jest jedynym źródłem zdarzeń kontrolnych.

Aby utrzymać zależności w czystości, powinniśmy postrzegać zewnętrzne wyzwalacze jako formę danych wejściowych użytkownika (niezamawianych) i przetwarzać je za pomocą tych samych ścieżek.

Jeśli użytkownik został w jakiś sposób poinformowany telepatycznie o dostępności nowych danych, mógł nacisnąć przycisk, aby go pobrać. Wtedy nie będzie potrzebny żaden przepływ sterowania wstecznego (taki jak powiadomienia push).

W tym idealnym świecie akcja użytkownika, aby uzyskać dane, została najpierw przechwycona na poziomie widoku, a następnie przeniesiona w dół.

To mówi nam, że powiadomienia powinny być obsługiwane przez kontroler widoku lub, jeszcze lepiej, komponent widoku przeznaczony do ich odbierania. Takie powiadomienia nie zawierają jednak żadnych danych, z wyjątkiem być może wskazania, która część modelu została unieważniona.

Powrót do FP to oczywiście gigantyczny efekt uboczny, jeśli weźmie się pod uwagę, że wszystkie wywołania funkcji będą zwracać potencjalnie różne wyniki. ALE ...

W matematyce, jeśli zdefiniujesz funkcję, która daje odległość pokonaną przy danej prędkości, ale nie podajesz parametru czasu, nie jesteś ofiarą efektu ubocznego, zapomniałeś jedynie dostarczyć wartość wejściowa.

Tak więc, jeśli weźmiemy pod uwagę, że wszystkie warstwy oprogramowania są czystymi funkcjami, ale ten czas jest niejawnym parametrem podanym przy początkowym wprowadzeniu, można sprawdzić, czy program jest zgodny z FP, sprawdzając, że powtarzające się połączenia, w dowolnej kolejności, do funkcji systemu, gdy czas jest zamrożony, powinien zawsze zwracać takie same wyniki.

Gdyby bazy danych mogły przechowywać w 100% kompletny zestaw migawek swoich stanów w danym czasie, możliwe byłoby sprawdzenie zgodności czystej aplikacji FP przez czas zamrażania lub uczynienie z niej parametru.

Powróć teraz do prawdziwego świata, taki wzór jest często niepraktyczny ze względu na wydajność. Wykluczałoby to jakąkolwiek formę buforowania.

Mimo to sugeruję, aby spróbować zakwalifikować powiadomienia jako niezamawiane dane wejściowe użytkownika w projekcie. Wierzę, że może to pomóc rozwiązać niektóre z zagadek.

+0

Więc zamiast tego, że "Interactor" obserwuje powiadomienia, mój "ViewController" (lub inny "Controller" w środku tych 2) byłby, prawda? Jeśli tak, to znaczy, że mój "Interaktor" będzie miał tylko jedno źródło danych wejściowych (jakaś metoda 'execute', która byłaby wywoływana), usuwając z niego obserwację (chociaż to nie zrobi wielkiej różnicy, ponieważ ja dzwoniłem tylko tak samo metoda 'execute' po nadejściu powiadomienia, więc metoda' execute' pozostaje taka sama). Ale nadal problem pozostaje, mój "Interactor" nadal uzyskuje dostęp do bazy danych. –

+0

Nie jestem pewien, czy uważasz, że prezenter jest częścią VC lub Modelu, ale jest tam w niewygodnej pozycji. Zwykle umieszczam przebudowę danych w warstwie modelu, tak aby VC mógł mieć bardzo naiwny widok wszechświata, gdzie wszystko zawsze istnieje, a jedynym stanem, jaki utrzymuje, jest minimum wymagane, aby wiedzieć, gdzie znajduje się użytkownik w tym wszechświecie. Jeśli twoje dane znajdują się na odległym serwerze, mogą pojawić się pewne problemy z wydajnością, ale powinieneś być w stanie stworzyć abstrakcję danych, które ukrywają wszystkie pobieranie i buforowanie do VC i utrzymują stany na minimalnym poziomie we wszystkich warstwach. –

+0

Ja tylko dodam prezenter, jeśli mój VC zacznie robić się zbyt duży. Ale wyobraź sobie UITableViewController, gdzie utrzymujesz tablicę z danymi? –

Powiązane problemy