Nazwa dla lekkich i ciężkich operacji

Odpowiedz Nowy wątek
2019-06-23 11:49
0

Otóż piszę funkcję która musi obsłużyć 10 przypadków

boolean check(Object o)

Dla 8 na 10 przypadków, operacja sprawdzająca jest bardzo szybka (kilkaset operacji na ms). Dla pozostałych 2óch na 10 przypadków szybka operacja sprawdzająca jest czasem nie wystarczająca, więc trzeba zrobić wolną operacją sprawdzającą. Kod powinien wyglądać tak:

boolean check(Object o) {
  if (szybka(o)) {
    return true;
  }
  return wolna(o);
}
  • Operacja szybka() potrafi tylko powiedzieć czy coś spełnia warunek:
    • true znaczy "na pewno spełnia"
    • false znaczy "nie wiadomo czy spełnia"
  • Operacja wolna() sprawdza już to na 100%:
    • true znaczy "na pewno spełnia"
    • false znaczy "na 100% nie spełnia"

No własnie, i nie wiem jak nazwać te metody, tak żeby było z samych nazw wiadomo:

  • Że szybka() jest optymalna, ale potrafi tylko powiedzieć "na pewno tak, ale nie wiadomo czy nie".
  • Że wolna() jest zasobożerna, ale potrafi na 100% ocenić poprawność.

Jakieś pomysły na nazwy?


edytowany 4x, ostatnio: TomRiddle, 2019-06-23 11:52
szybkaNiedokladnaOptymalna(); wolnaDokladnaNieoptymalna() xD - au7h 2019-06-23 11:55

Pozostało 580 znaków

2019-06-24 11:46
1

Pytanie czy ta szybka a niepewna w ogóle będzie przydatna, czy tylko tworzysz ją jako wadliwą optymalizację? :)

Pozostało 580 znaków

2019-06-24 11:52
2
  • heurestic_check
  • check

Pozostało 580 znaków

2019-06-24 11:56
0

Co jest ważne dla czytelnika? To CO funkcja robi, czy JAK to robi? Może po zmianach przez innego developera, już nie będzie taka "quick" / "slow" :-)

Pozostało 580 znaków

2019-06-24 12:16
0

A to są publiczne metody czy tylko wewnętrzna implementacja?


Spring? Ja tam wole mieć kontrole nad kodem ᕙ(ꔢ)ᕗ
Haste - mała biblioteka do testów z czasem.

Pozostało 580 znaków

2019-06-24 13:21
V-2
8
TomRiddle napisał(a):
  • Operacja szybka() potrafi tylko powiedzieć czy coś spełnia warunek:
    • true znaczy "na pewno spełnia"
    • false znaczy "nie wiadomo czy spełnia"
  • Operacja wolna() sprawdza już to na 100%:
    • true znaczy "na pewno spełnia"
    • false znaczy "na 100% nie spełnia"

Żadna z propozycji podanych w tym temacie mi się nie podoba.

Shallow, deep, heuristic, "sensitive and specific"... Ilu programistów poprawnie zrekonstruuje z tych terminów tę rozpiskę, którą podałeś powyżej? :)

"With false negatives" jest lepsze, ale rozwlekłe, wymaga chwili namysłu. Na dodatek ma wydźwięk, który - przynajmniej dla mnie - sugeruje nieprawidłowe działanie metody.

Kiedy znalezienie dobrych nazw stanowi problem, czasem warto zrobić krok do tyłu i zastanowić się, czy nie trzeba zmienić podejścia. Może problem wynika z prób upakowania trzech możliwych odpowiedzi w wartości boolean, których znaczenie zmienia się kontekstowo?

Może powinno być np. tak, że szybka metoda zwraca Optional<Boolean>. A wolna - Boolean.

Ważną informację przenosimy w ten sposób do sygnatur tych metod. Staje się oczywiste, że metoda szybka udziela odpowiedzi niepewnej. Dopilnuje tego sam silnik typów.

I odpada problem, że false miewa dwa różne znaczenia zależnie od kontekstu. Co wcześniej mogło zdezorientować.

Znalezienie nazwy staje się wtedy łatwiejsze, bo:

nie wiem jak nazwać te metody, tak żeby było z samych nazw wiadomo:

  • Że szybka() jest optymalna, ale potrafi tylko powiedzieć "na pewno tak, ale nie wiadomo czy nie".
  • Że wolna() jest zasobożerna, ale potrafi na 100% ocenić poprawność.

Od tej pory nie masz już tego "ale". Teraz nazwa musi oddać tylko pierwszą różnicę. Druga wynika z sygnatury metody.

Możliwe nazwy:

Optional<Boolean> quicklyConfirm(Object o);

Boolean exhaustivelyConfirm(Object o);

A wtedy:

boolean check(Object o) {
  if (szybka(o)) {
    return true;
  }
  return wolna(o);
}

Zmieni się w:

boolean check(Object o) {
  return quicklyConfirm(o)
          .orElseGet(() -> exhaustivelyConfirm(o));
}

Wytknąć można jedno niedociągnięcie - kwestia dyskusji i gustu, czy w praktyce istotne. W praktyce quicklyConfirm może zwrócić: Optional.of(true) albo Optional.empty()*.

Rezultat Optional.of(false) jest niemożliwy. Ale to nie wynika już ani z nazwy, ani z sygnatury. Dotarliśmy do limitu tego, co może wyrazić boolean. Nawet udekorowany trójwartościowością.

Jeśli jesteśmy nieco pedantyczni i nam to przeszkadza...

...możemy pokusić się o jeszcze ściślejsze podejście.

Na przykład - używając Javy:

public class ConfirmationResult {
    public interface ConfirmationStatus {
        Optional<Boolean> value();
    }

    public enum Quick implements ConfirmationStatus {
        CONFIRMED,
        UNKNOWN;

        @Override
        public Optional<Boolean> value() {
            if (this == CONFIRMED) {
                return Optional.of(true);
            }
            return Optional.empty();
        }
    }

    public enum Exhaustive implements ConfirmationStatus {
        CONFIRMED,
        REJECTED;

        @Override
        public Optional<Boolean> value() {
            return Optional.of(this == CONFIRMED);
        }
    }
}

I teraz:

ConfirmationResult.Quick quicklyConfirm(Object o);

ConfirmationResult.Exhaustive exhaustivelyConfirm(Object o);

Oba enumy wspierają ten sam interfejs, więc mają wspólny mianownik: ConfirmationStatus, więc można tę wartość podawać - i wyciągnąć z niej Optional<Boolean> - nie interesując się kompletnie, czy jest to instancja Quick, czy Exhaustive.

A zarazem nie sposób się w żaden sposób pomylić. Wszystko jest udokumentowane na poziomie typów i definicji. if (exhaustivelyConfirm(o) == ConfirmationResult.Quick.UNKNOWN) nawet się nie zbuduje. if (quicklyConfirm(o) == ConfirmationResult.Exhaustive.REJECTED) nawet się nie zbuduje.

Można, jeśli potrzebujemy, napisać sobie nawet szybką "porównywarkę" dla instancji ConfirmationStatus, która umożliwiłaby łatwe porównania między wartościami obu enumów. Jest to Java, więc niestety wszędzie włazi nam pełno boilerplate'u. Ale z tym męczy się pół świata i na to już nie ma prostej rady.


  • Na potrzeby poglądowe używam jakiejś bibliotecznej wersji Optionala, bo akurat jest dodana do projektu, który mam otwarty w IDE. Więc tak mi prościej. Your naming may vary.

Nie ma najmniejszego powodu, aby w CV pisać "email" przed swoim adresem mailowym, "imię i nazwisko" przed imieniem i nazwiskiem" ani "zdjęcie mojej głowy od przedniej strony" obok ewentualnego zdjęcia.
edytowany 10x, ostatnio: V-2, 2019-06-24 14:07

Pozostało 580 znaków

2019-06-24 14:21
0

Chciałbym uroczyście podziękować @V-2 za duży wkład wysiłku w miarodajną odpowiedź! Dałbym super-łapkę, gdyby była taka możliwość.

V-2 napisał(a):
TomRiddle napisał(a):
  • Operacja szybka() potrafi tylko powiedzieć czy coś spełnia warunek:
    • true znaczy "na pewno spełnia"
    • false znaczy "nie wiadomo czy spełnia"
  • Operacja wolna() sprawdza już to na 100%:
    • true znaczy "na pewno spełnia"
    • false znaczy "na 100% nie spełnia"

Żadna z propozycji podanych w tym temacie mi się nie podoba.

Shallow, deep, heuristic, "sensitive and specific"... Ilu programistów poprawnie zrekonstruuje z tych terminów tę rozpiskę, którą podałeś powyżej? :)

"With false negatives" jest lepsze, ale rozwlekłe, wymaga chwili namysłu. Na dodatek ma wydźwięk, który - przynajmniej dla mnie - sugeruje nieprawidłowe działanie metody.

Kiedy znalezienie dobrych nazw stanowi problem, czasem warto zrobić krok do tyłu i zastanowić się, czy nie trzeba zmienić podejścia. Może problem wynika z prób upakowania trzech możliwych odpowiedzi w wartości boolean, których znaczenie zmienia się kontekstowo?

W zupełności się zgadzam.

Może powinno być np. tak, że szybka metoda zwraca Optional<Boolean>. A wolna - Boolean.

Ważną informację przenosimy w ten sposób do sygnatur tych metod. Staje się oczywiste, że metoda szybka udziela odpowiedzi niepewnej. Dopilnuje tego sam silnik typów.

Pytanie czy jest sens zmieniać proste sygnatury boolean a(), boolean b() na bardziej skomplikowane, po to żeby były bardziej wymowne? Dodatkowo z tym optionalem, może być albo optional udany true, albo nie udany. Nie ma optional'a udanego false - jaki by to miało sens?

A zarazem nie sposób się w żaden sposób pomylić. Wszystko jest udokumentowane na poziomie typów i definicji. if (exhaustivelyConfirm(o) == ConfirmationResult.Quick.UNKNOWN) nawet się nie zbuduje. if (quicklyConfirm(o) == ConfirmationResult.Exhaustive.REJECTED) nawet się nie zbuduje.

Też o tym myślałem, żeby składania języka sama wymuszała poprawne użycie wyniku, i uniemożliwiała użycie tego false jako "false", zamiast jako "nie wiadomo czy false". To by było bardzo fajne! gdyby nie to że bardzo skomplikowane :/


Ale z tymi enumami, stary to pojechałeś :D Super over-engineering, dla dwóch metod. Niestety, nie chcę tak komplikować jednego prostego algorytmu.

Niemniej - bardzo doceniam to że włożyłeś wysiłek w przemyślenie, analizę problemu i kilka sensownych propozycji. Również doceniam to że ważna była dla Ciebie forma, widać to po 10x edytowany tekst :D

Dziękuję.


edytowany 3x, ostatnio: TomRiddle, 2019-06-24 14:24

Pozostało 580 znaków

2019-06-24 14:24
0
TomRiddle napisał(a):
Afish napisał(a):

isYadaYadaWithFalseNegatives oraz isYadaYada..

Nazwa nie pokazuje czemu ktoś miałby użyć pierwszej (jest szybka).

isYadaYadaFastCheckWithFalseNegatives.

Od takich rzeczy jest dokumentacja, bo:

  • Co znaczy „szybko”? Jak to zostało sprawdzone i według jakich kryteriów?
  • Skąd wiadomo, że „szybko” jest ciągle poprawne? A może od czasu testów coś się zmieniło i już nie jest szybko.
  • Dlaczego nie zawsze jest poprawny wynik? W jakich sytuacjach jest niepoprawny? Jak często ta sytuacja występuje?
  • Dlaczego w ogóle używać szybkiej metody? Może zysk nie jest wart trzymania dwóch algorytmów?

Pozostało 580 znaków

2019-06-24 14:28
0
Afish napisał(a):

Od takich rzeczy jest dokumentacja, bo:

No przykro mi, ale nie tak mnie uczono programować. Jeśli mogę coś wyrazić dobrze w nazwie funkcji, to wolałbym to zrobić, niż olewać problem i pchać jakieś mało mówiące wyjaśnienie do zewnętrznego źródła, jakim jest dokumentacja. Polecam przeczytać "Clean Code".

  • Co znaczy „szybko”? Jak to zostało sprawdzone i według jakich kryteriów?

Szybko znaczy hashMap.containsKey('key').

  • Skąd wiadomo, że „szybko” jest ciągle poprawne? A może od czasu testów coś się zmieniło i już nie jest szybko.

Jestem przekonany że wyciąganie czegoś z hash mapy po kluczu jest wystarczająco szybkie :D

  • Dlaczego nie zawsze jest poprawny wynik? W jakich sytuacjach jest niepoprawny? Jak często ta sytuacja występuje?

Nie mówiłem że jest "niepoprawny". Mówiłem że jest niepewny.

Jeśli klucz w mapie jest, znaczy że to co sprawdzam istnieje na 100%. Jeśli nie ma w mapie - to znaczy że może jest, może nie ma i trzeba wykonać ciężą operację żeby się upewnić. Około 80% przypadków jest już pre-loaded w mapie.

  • Dlaczego w ogóle używać szybkiej metody? Może zysk nie jest wart trzymania dwóch algorytmów?

Bo to szybki special-case, i warto zaoszczędzić trochę procesora/zasobów.

Fetchowanie tego drugi raz korzysta z zasobów IO systemowych (i czasami z socketów) - bez sensu jest wykonywanie tej drugiej operacji zawsze.


edytowany 4x, ostatnio: TomRiddle, 2019-06-24 14:34

Pozostało 580 znaków

2019-06-24 14:30
V-2
0
TomRiddle napisał(a):

Chciałbym uroczyście podziękować @V-2 za duży wkład wysiłku w miarodajną odpowiedź! Dałbym super-łapkę, gdyby była taka możliwość.

Cieszę się że mogłem pomóc, albo zainspirować; dzięki

Może powinno być np. tak, że szybka metoda zwraca Optional<Boolean>. A wolna - Boolean.

Ważną informację przenosimy w ten sposób do sygnatur tych metod. Staje się oczywiste, że metoda szybka udziela odpowiedzi niepewnej. Dopilnuje tego sam silnik typów.

Pytanie czy jest sens zmieniać proste sygnatury boolean a(), boolean b() na bardziej skomplikowane, po to żeby były bardziej wymowne?

Coś za coś... Nie widzę możliwości spełnienia wszystkich wymogów naraz. Zwięzłe nazwy / zrozumiałe na pierwszy rzut oka API / najprostsze możliwe sygnatury... pick two :)

Sygnatury w "skromniejszej" wersji rozwiązania - czyli boolean i Optional<Boolean> - nie są zresztą aż tak skomplikowane.

Dodatkowo z tym optionalem, może być albo optional udany true, albo nie udany. Nie ma optional'a udanego false - jaki by to miało sens?

Optional(false) znaczy "zweryfikowany negatywnie", "wykluczony". Kot nie żyje.

Być może nazwy należałoby oprzeć na czasowniku np. "verify" zamiast "confirm".

Ale z tymi enumami, stary to pojechałeś :D Super over-engineering, dla dwóch metod. Niestety, nie chcę tak komplikować jednego prostego algorytmu.

Nie jestem takim purystą, pokazałem tylko możliwość :) To podejście znane z programowania funkcyjnego: możliwie jak najwięcej wyspecyfikować za pomocą typów. Java jest niestety bardzo rozwlekłym językiem. Są takie, w których dałoby się to samo wyrazić znacznie zwięźlej.

Jeśli znajdziesz zgrabniejsze rozwiązanie, wrzuć proszę do tematu (z ciekawości)


Nie ma najmniejszego powodu, aby w CV pisać "email" przed swoim adresem mailowym, "imię i nazwisko" przed imieniem i nazwiskiem" ani "zdjęcie mojej głowy od przedniej strony" obok ewentualnego zdjęcia.

Pozostało 580 znaków

2019-06-24 14:31
0
V-2 napisał(a):

Jeśli znajdziesz zgrabniejsze rozwiązanie, wrzuć proszę do tematu (z ciekawości)

Raczej zostawię ify i znajdę dobre nazwy funkcji, zamiast zmieniać sygnatury :) Ale jeszcze raz dziękuję za wkład w odpowiedź.

Głównie dlatego że Optional.of(true)/Optional.empty() jest semantycznie równy true/false, więc nie specjalnie chciałbym go użyć.

PS: Tak, zdaję sobie sprawę że of(true)/of(false)/empty() jest semantycznie równy true/false/null - ten sam case :D Ale coś mi mówi że z dwoma przypadkami to ma mniejszy sens. Nie potrafię wyjaśnić czemu.


edytowany 3x, ostatnio: TomRiddle, 2019-06-24 14:33

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

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