Gdzie umieszczamy kod „pytając świat”, kiedy oddzielamy obliczenia od skutków ubocznych?

10

Zgodnie z zasadą rozdzielania zapytań , a także Myślenia w danych i DDD z prezentacjami Clojure, należy oddzielić skutki uboczne (modyfikujące świat) od obliczeń i decyzji, aby łatwiej było zrozumieć i przetestować obie części.

Pozostawia to pytanie bez odpowiedzi: gdzie w stosunku do granicy powinniśmy postawić „zadawanie światu”? Z jednej strony żądanie danych z systemów zewnętrznych (takich jak baza danych, interfejsy API usług zewnętrznych itp.) Nie jest względnie przejrzyste, a zatem nie powinno współdziałać z czystym kodem obliczeniowym i decyzyjnym. Z drugiej strony problematyczne, a może niemożliwe, jest dokuczanie im poza częścią obliczeniową i przekazywanie go jako argumentu, ponieważ możemy nie wiedzieć z góry, o które dane możemy poprosić.

Alexey
źródło
1
Właśnie tutaj pojawiają się koncepcje wywołań zwrotnych. Jeśli nie wiesz z góry, jakie dane mogą być potrzebne, zapewnij wywołanie zwrotne do kodu obliczeniowego, w którym może on określić, jakich danych potrzebuje, i umożliwić innym warstwom faktyczne pobieranie i udostępnianie . Jeśli musi być asynchroniczny, wywołanie zwrotne może nawet określić inną funkcję do wywołania z pobranymi danymi, gdy staną się one dostępne.
Marjan Venema
1
@MarjanVenema, to jedyna opcja, która przychodzi mi do głowy. Z teoretycznego punktu widzenia: jeśli metoda, w przeciwnym razie pozbawiona skutków ubocznych, wywołuje wywołanie zwrotne wywołujące skutki uboczne, staje się skuteczna. Prawdopodobnie moim problemem jest to, że zakładam, że obliczenia separacji od skutków ubocznych wymagają, aby obliczenia były względnie przejrzyste. Chociaż nie jest to konieczne, prawda.
Alexey,
1
Jeśli tak się martwisz, twoje obliczenia po prostu nie są wystarczająco szczegółowe. Musisz wyodrębnić decyzję dotyczącą tego, jakie inne dane / kroki są potrzebne. Podziel więc pełne obliczenia na etapy w zależności od tego, gdzie podejmowane są decyzje, które dane są potrzebne. Następnie mieć pewnego rodzaju „reżysera”, który zarządza przepływem pracy dla pełnego obliczenia: rozpoczynając każdy krok, odzyskując informacje z każdego kroku, używając tego do decydowania o następnym kroku i potrzebnych danych, rozpoczynając proces pobierania, aby go uzyskać, a następnie przekazując pobrane dane do następnego kroku w obliczeniach.
Marjan Venema

Odpowiedzi:

1

Z drugiej strony problematyczne, a może niemożliwe, jest dokuczanie im poza częścią obliczeniową i przekazywanie go jako argumentu, ponieważ możemy nie wiedzieć z góry, o które dane możemy poprosić.

Jest to przypadek, w którym, jak zauważono w komentarzach, przekazanie możliwości pobierania danych (np. Funkcja pierwszej klasy, obiekt implementujący interfejs itp.) Zapewnia wygodny mechanizm izolowania skutków ubocznych.

Funkcja wyższego rzędu, której ciało jest czyste, ma nieokreśloną czystość: http://books.google.com/books?id=Yb8azEfnDYgC&pg=PA143#v=onepage&q&f=false

Pisałem o tym, nazywając ten typ funkcji potencjalnie czystą funkcją: http://adamjonrichardson.com/2014/01/13/potentional-pure-functions/

Jeśli połączysz potencjalnie czystą funkcję z funkcjami awaryjnymi (które nie mają rozgałęzionych konstrukcji i wykonują jak najmniej), kombinację nazywam zestawami izolacyjnymi, możesz dość skutecznie izolować skutki uboczne i tworzyć bardzo testowalny kod: http: // adamjonrichardson.com/2014/01/15/isolating-side-effects-using-isolation-sets/

Adam
źródło
0

Przechowujesz wynik w klasie, na początku wydaje się to nieco dziwne, ale skutkuje prostszym kodem. np. brak zmiennych tymczasowych w obiekcie wywołującym.

class database_querier
    feature -- queries
        was_previous_query_ok : boolean is
            do
                Result = …
            end

        previous_query_result : string is 
            requires
                was_previous_query_ok
            do
                Result = query_result
            end

    feature -- commands
        query_db (…) is
            do
                …
                query_result = bla
            end

    feature {none} --data
        query_result : string
ctrl-alt-delor
źródło
1
Uwielbiam widzieć Eiffla na wolności.
SBI
@sbi to tylko pseudo kod. :-)
ctrl-alt-delor
Wystarczająco blisko, by mnie uszczęśliwić;)
SBI