Pochodzenie „metoda powinna zwrócić wartość lub mieć skutki uboczne, ale nie jedno i drugie”

12

Przeczytałem kiedyś, że metoda powinna albo mieć wartość zwracaną (i być referencyjnie przezroczysta), albo mieć skutki uboczne, ale nie jedno i drugie. Nie mogę znaleźć żadnych odniesień do tej reguły, ale chcę dowiedzieć się więcej na jej temat.

Jakie jest pochodzenie tej porady? Z jakiej osoby lub społeczności powstało?

Dodatkowy kredyt: Jaka jest domniemana korzyść wynikająca z zastosowania tej porady?

Wayne Conrad
źródło
1
@gnat Tak, chodzi przede wszystkim o historię. Obawiałem się, że dodatkowa część kredytu była zbyt subiektywna, by stać sama, i że historia ma większą szansę na uniknięcie zamknięcia. Dodam tag.
Wayne Conrad
niektóre odpowiedzi, które się na nim nakładają, sprawiły, że zastanawiałem się, czy pytasz o zasiłek, o który wystąpił autor tej porady, czy o listę wszystkich świadczeń, o które w ogóle można się ubiegać?
komara
@gnat Pytam o korzyść zgłoszoną przez autora (ponownie, obawiając się zamknięcia), ale na pewno nie mam nic przeciwko przyczynom nakładania się - odpowiadają na pytanie, które naprawdę chciałem zadać. Gdybym usunął z mojego pytania „twierdził”, stawiając stosowe odpowiedzi na temat, czy przesuwałoby to pytanie zbyt głęboko w subiektywne?
Wayne Conrad,
„powody nakładania” prawdopodobnie spowodują, że pytanie zostanie zamknięte jako zbyt ogólne . Jeśli wolisz, aby „pozostać na otwartej stronie”, myślę, że bezpieczniej byłoby zawęzić go do korzyści, o które wnioskował autor
gnat
Jedną z korzyści jest to, że jeśli płacisz według objętości kodu, to daje dodatkowe. „doSomething; GetResultOfSomething; HandleErrorsFromSomething;”

Odpowiedzi:

13

Według Grega Younga pomysł ten wywodzi się z Bertrand Meyer : rozdzielenie poleceń i zapytań .

Stwierdza, że ​​każda metoda powinna być albo komendą wykonującą akcję, albo zapytaniem zwracającym dane do programu wywołującego, ale nie jednym i drugim. Innymi słowy, zadanie pytania nie powinno zmienić odpowiedzi . 1 Bardziej formalnie, metody powinny zwracać wartość tylko wtedy, gdy są referencyjnie przejrzyste, a zatem nie wywołują skutków ubocznych.

1: Eiffel: język slajdu inżynierii oprogramowania 43-48

W projektowaniu opartym na domenie jest to podobne do rozdzielania / segregacji poleceń i zapytań (CQRS), jak nazwał to Greg Young.

Greg Young wpadł na pomysł CQS od Bertrand, aby nazwać CQRS, jak wspomniał Martin Fowler w tym artykule CQRS

Korzyści

  • Część Read (Query) można skalować / modyfikować inaczej niż część Write (command). Rozdzielenie tych dwóch zapobiegnie wzajemnemu przeszkadzaniu, gdy kluczowa jest optymalizacja / wydajność.

Przeczytaj artykuł w linku Martina Fowlera, aby uzyskać więcej.

tunmise fasipe
źródło
1
Oczywiście w wielu sytuacjach generowanie użytecznego wyniku i dokonywanie modyfikacji w tym samym czasie nie jest droższe niż robienie trudniejszego z nich osobno.
Deduplicator
1
@Deduplicator Przykładem stereotypu jest InterlockedCompareExchange?
1
Ta rada oczywiście nie ma zastosowania, gdy zwracana jest pewna informacja o tym, co zostało zrobione w poleceniu, jednak metoda usuwania wierszy z zestawu danych może zasadniczo zmienić stan zestawu danych, usuwając wskazane wiersze zgodnie z podanymi kryteriami, i następnie zwróć liczbę usuniętych wierszy lub nawet listę ze wspomnianymi wierszami.
T. Sar
4

Nie wiem, skąd pochodzi, ale jest to dobra rada i dość prosta do zrozumienia.

Każdy rozsądnie zaprojektowany program zostanie podzielony na różne części, połączone i skomponowane na różne sposoby. Im trudniej jest zrozumieć, co robi konkretna część, tym trudniej jest upewnić się, że Twój program zareaguje w przewidywalny sposób.

Izolowanie części, które wywołują skutki uboczne, ułatwia reszcie racjonalizację, testowanie i debugowanie. Zmniejszenie liczby efektów ubocznych w każdej części, która generuje efekt uboczny, ułatwi pracę z tą częścią w ten sam sposób.

Jeśli rozłożysz go jeszcze bardziej, wartość zwrotna jest efektem. Skutki uboczne są efektem. Funkcja powinna dawać tylko 1 efekt (jeśli to możliwe), ponieważ im większa liczba danych wejściowych i efektów, tym większa trudność w uzasadnieniu tego, co faktycznie robi.

Morgen
źródło
to nawet nie próbuje odpowiedzieć na zadane pytanie, patrz Jak odpowiedzieć
gnat
@gnat moje pytanie przyszedł w dwóch częściach: Pytanie główne ( „kto”), a dodatkowy kredyt ( "dlaczego) nie ten adres dodatkową część kredytowej.?
Wayne Conrada
według mojej lektury („ domniemana korzyść”) oczekuje się, że część zostanie zaproponowana przez autora cytatu. Wydaje się, że pytanie nie wymaga podania listy wszystkich możliwych korzyści
komara
2
@gnat Zrozumiałem pytanie jako próbę zrozumienia tej rady, zarówno jej przyczyny, jak i kontekstu, w którym została podana. Nie sądzę, aby niewłaściwe było zajmowanie się tylko częścią pytania.
Morgen,
1

Dodatkowy kredyt: Jaka jest pierwotnie deklarowana korzyść wynikająca z zastosowania tej porady?

Jedną z korzyści oddzielenia wartości zwrotu od skutków ubocznych jest to, że usuwa potencjalny problem, który może być spowodowany oceną zwarcia .

bool FooWithSideEffect() {
    // do query
    // do side effect
    return resultOfQuery;
}

bool BarWithSideEffect() {
    // do query
    // do side effect
    return resultOfQuery;
}

void BadShortCircuitEvaluation()
{
    // the programmer's intent is to have side effects of both functions
    if (FooWithSideEffect() && BarWithSideEffect() ) {
        // do something
    }

    // in case FooWithSideEffect() returns true, 
    // then BarWithSideEffect() is not called at all
    // because of short-circuit evaluation
}
Nick Alexeev
źródło
czy jest to korzyść wnioskowana przez autora porady ?
komara
@gnat Mam mieszane historyczne i praktyczne, obawiam się.
Nick Alexeev
1
komentarz i kod nie są zgodne, BarWithSideEffects nie jest wywoływane, jeśli FooWithSideEffects zwraca false
jk.