Bardzo krótkie metody

Bardzo krótkie metody
Madness
  • Rejestracja:prawie 10 lat
  • Ostatnio:2 miesiące
  • Postów:118
0

Ciekawi mnie co doświadczony programista sądzi o takich metodach?
Dobry kod powinien być czytelny i zrozumiały po samych nazwach klas/metod/zmiennych, ale czy powinno się praktykować 1-liniowe metody?

Dla przykładu:

Kopiuj
public static boolean fileExist(String fileName) {
        return new File(fileName).isFile();
    }

    public static boolean isEven(int number) {
        return number % 2 == 0;
    }

    public static float averageLineLength(int charsSum, int linesSum) {
        return charsSum / linesSum;
    }
edytowany 1x, ostatnio: Adam Boduch
SL
  • Rejestracja:ponad 19 lat
  • Ostatnio:ponad 6 lat
  • Lokalizacja:Bydgoszcz
2

Ja uważam że nie ma co przeginać, bo:

  1. Metody powinny być krótkie, ale w tym przypadku możesz zataić co masz na myśli, każdy myśli że isEven zwróci liczbę parzystą ale jak coś skopiesz w tej metodę to wprowadzisz wiele osób w błąd.
  2. Nie powiem żeby to było dużo czytelniejsze (w przypadku dwóch ostatnich metod)
  3. Metody statyczne to w cale nie jakieś mistrzostwo w programowaniu obiektowym.
  4. Wydajność.... niby nic wielkiego - jedna linijka, ale jednak trzeba odłożyć skok do metody i obsługę wyników na stosie/stercie.

Dobre są 4-5 linijkowe metody, te nico dłuższe też, ale jednolinijkowece?


Bydgoszcz, Senior .Net Developer
edytowany 1x, ostatnio: Slepiec
flowCRANE
„[…] każdy myśli że isEven zwróci liczbę parzystą […]” – każdy myśli, że metoda poprzedzona prefiksem is zwraca wartość logiczną.
LukeJL
  • Rejestracja:około 11 lat
  • Ostatnio:2 minuty
  • Postów:8408
3

pytanie czy naprawdę potrzeba tutaj osobnej metody, czy nie lepiej po prostu napisać number % 2 == 0 itp. niż komplikować i używać metody.

Myślę, że jak zwykle odpowiedzią jest "to zależy".

w przypadku isEven zapewne zysk będzie zerowy, ale już np. zenkapsulowanie sprawdzania czy plik istnieje w postaci metody fileExist może mieć sens, jeśli będziesz chciał pobawić się potem w polimorfizm i np. obsługę różnych systemów plików. Ale to sam musisz sie za każdym razem zastanowić co ma większy sens w danym przypadku.

W przypadku averageLineLength to szczerze powiedziawszy coś tu jest nie halo. Taka funkcja chyba powinna przyjmować jakiegoś rodzaju kolekcję stringów a nie dwa inty? Mnie się wydaje, że zły poziom abstrakcji tu przyjąłeś.


Wibowit
  • Rejestracja:prawie 20 lat
  • Ostatnio:około 3 godziny
17

Zależy od długości i stopnia wykorzystania. Np 1-linijkowe metody używane w jednym miejscu zwykle nie miałyby sensu - takie metody można zastąpić po prostu zmiennymi. Jednak w wielu przypadkach jednolinijkowe metody mają sens, bo opisują co robi dany kod.

Taki kod nie ma sensu, bo nazwa metody nie wnosi nic co jest natychmiastowo widoczne w ciele metody:

Kopiuj
void multiplyNumbers(int a, int b) {
  return a * b;
}

Ale taka metoda już coś wnosi:

Kopiuj
boolean userCanEditItem(User user, Item item) {
  return user.isAdmin() || user.manageableItemTypes.contains(item.type);
}

bo zdecydowanie szybciej jestem w stanie zrozumieć to:

Kopiuj
if (!userCanEditItem(user, item)) {
  throw new Error("illegal operation");
}

niż to:

Kopiuj
if (!(user.isAdmin() || user.manageableItemTypes.contains(item.type))) {
  throw new Error("illegal operation");
}

Nie muszę się domyślać, że chodzi o prawa dostępu, bo wynika to wprost z nazwy metody.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 1x, ostatnio: Wibowit
azalut
uff dobrze, że to napisałes bo chciałem napisać to samo a mi sie pisać nie chciało :D zgadzam się, thumb up!
AF
  • Rejestracja:prawie 18 lat
  • Ostatnio:18 dni
1
Slepiec napisał(a):

Metody powinny być krótkie, ale w tym przypadku możesz zataić co masz na myśli, każdy myśli że isEven zwróci liczbę parzystą ale jak coś skopiesz w tej metodę to wprowadzisz wiele osób w błąd.

Jak skopiesz w innym miejscu, to też wprowadzisz w błąd.

Slepiec napisał(a):

Metody statyczne to w cale nie jakieś mistrzostwo w programowaniu obiektowym.

Do sprawdzenia podzielności liczby nie trzeba kontenera DI i fabryki strategii.

Slepiec napisał(a):

Wydajność.... niby nic wielkiego - jedna linijka, ale jednak trzeba odłożyć skok do metody i obsługę wyników na stosie/stercie.

Tym się zajmuje kompilator, poza tym szanujące się platformy i tak nie zrobią żadnego wywołania metody.

SL
  • Rejestracja:ponad 19 lat
  • Ostatnio:ponad 6 lat
  • Lokalizacja:Bydgoszcz
0
Afish napisał(a):
Slepiec napisał(a):

Metody powinny być krótkie, ale w tym przypadku możesz zataić co masz na myśli, każdy myśli że isEven zwróci liczbę parzystą ale jak coś skopiesz w tej metodę to wprowadzisz wiele osób w błąd.

Jak skopiesz w innym miejscu, to też wprowadzisz w błąd.

Tak ale jak skopiesz w metodzie która powinna być oczywista a nie jest, to chyba gorzej.

Slepiec napisał(a):

Metody statyczne to w cale nie jakieś mistrzostwo w programowaniu obiektowym.

Do sprawdzenia podzielności liczby nie trzeba kontenera DI i fabryki strategii.

Do oczywistych rzeczy nie trzeba takich metod wcale.

Slepiec napisał(a):

Wydajność.... niby nic wielkiego - jedna linijka, ale jednak trzeba odłożyć skok do metody i obsługę wyników na stosie/stercie.

Tym się zajmuje kompilator, poza tym szanujące się platformy i tak nie zrobią żadnego wywołania metody.

Tak, owszem, obyśmy mieli do czynienia tylko z szanującymi się platformami :D


Bydgoszcz, Senior .Net Developer
edytowany 1x, ostatnio: Slepiec
AF
  • Rejestracja:prawie 18 lat
  • Ostatnio:18 dni
1
Slepiec napisał(a):

Tak ale jak skopiesz w metodzie która powinna być oczywista a nie jest, to chyba gorzej.

Jak dla mnie w obu miejscach jest to samo, a jak nie wyjdzie na testach i przeglądzie kodu, to nieużycie małej metody i tak nie pomoże.

Slepiec napisał(a):

Do oczywistych rzeczy nie trzeba takich metod wcale.

Nie chodzi o oczywistość, tylko o czytelność. Dla jednego użycie operatora modulo będzie czytelne, inny użyje koniunkcji bitowej, a jeszcze inny metody z biblioteki standardowej. Zależy od zespołu.

Slepiec napisał(a):

Tak, owszem, obyśmy mieli do czynienia tylko z szanującymi się platformami :D

To wtedy masz o wiele większe problemy, niż jakieś tam wywołanie metody, do tego platforma może wreszcie zacząć się szanować i wprowadzać optymalizacje, a ręczne inlineowanie metod wcale nie jest optymalizacją.

Wibowit
  • Rejestracja:prawie 20 lat
  • Ostatnio:około 3 godziny
6

Metody powinny być krótkie, ale w tym przypadku możesz zataić co masz na myśli, każdy myśli że isEven zwróci liczbę parzystą ale jak coś skopiesz w tej metodę to wprowadzisz wiele osób w błąd.

Nazwa isEven jest zła, bo jest zbyt oczywista? To może nazwa hasMagicalProperty byłaby lepsza? Wtedy nikt nie byłby przesadnie pewny siebie, ba każdy byłby podejrzliwy i sprawdzałby ciało metody.

Jeśli metoda jest skopana to znaczy, że:

  • była słabo wytestowana (prawdopodobnie wcale, bo łatwe metody łatwo się testuje)
  • wystarczy poprawić kod w jednym miejscu, a nie w wielu

Aczkolwiek robienie metody isEven to już nieco przegięcie. Myślę, że przez takie kiepskie przykłady dyskusja nad krótkimi metodami idzie w złym kierunku.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 3x, ostatnio: Wibowit
vpiotr
Akurat patrzę na funkcję która w tym przypadku nazywałaby się doWithoutOddFiltering (#!#!$%&).
EP
  • Rejestracja:prawie 8 lat
  • Ostatnio:ponad 6 lat
  • Postów:122
0

Po prostu zmieść całą metodę w jednym ekranie lub mniej. Tworzenie miliona jednolinijkowych metod to przesada w drugą stronę, bo nie bardzo wyobrażam sobie analizę takiego kodu potem.


Wenn ist das Nunstück git und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt gersput!
Zobacz pozostałe 6 komentarzy
LukeJL
mnie się mieszczą 42 linijki, ale pracuję na laptopie 13 cali.
LukeJL
Myślę, że to zależy co robimy. Czasem 1000 linijek kodu w jednej klasie mogłoby być okej (co prawda w większości przypadków 1000 linijek kodu w jednej klasie będzie to spaghetti i big ball of mud, ale przynajmniej w teorii ktoś mógłby zrobić taką klasę, która ładnie by wyglądała pomimo np. tysiąca linii - ale najprostszy sposób osiągnięcia tego to pisanie prostego kodu, np. deklaracja stałych. Klasa, która ma 1000 linijek kodu, ale 900 linijek to będą deklaracje stałych (a nie żadna głębsza logika) będzie jak najbardziej okej.
Maciej Cąderek
Maciej Cąderek
@caer TO chyba masz monitor w pionie albo z lupą programujesz ;)
EP
U mnie w sumie bez zsunięcia pasków to 25 :P Ale pracuję na lapku to raz, a jak się zsunie jakieś okna to zbliżam się do poziomu @LukeJL
caer
No w pionie, a jak inaczej? :P
Madness
  • Rejestracja:prawie 10 lat
  • Ostatnio:2 miesiące
  • Postów:118
0

Ja tylko spytałem o opinię, nie chciałem niczego złego :D W każdym razie dziękuję za każdą odpowiedź! Myślę, że dyskusję można zakończyć.

LukeJL
  • Rejestracja:około 11 lat
  • Ostatnio:2 minuty
  • Postów:8408
1

Ja mam taką metauwagę:

Dobry kod powinien być czytelny i zrozumiały po samych nazwach klas/metod/zmiennych,

dobry kod nie musi być czytelny po samych nazwach klas, bo może być czytelny na poziomie samego języka. I teraz:
number % 2 == 0;

Myślę, że dla każdego programisty, który jest w stanie napisać fizz-buzz (klasyczne zadanie sprawdzające, czy znasz podstawy programowania), zapis number % 2 będzie zrozumiały. Tak samo jeśli masz kod a + b to nie musisz wydzielać go do funkcji addTwoNumbers(a, b) bo to by tylko zaciemniło kod.

Nie ma nic złego w używaniu operatorów matematycznych (czy innych) istniejących w języku. Po to one są w końcu. To operatory są już same w sobie cukrem składniowym i świadczą o tym, że programujemy w języku wysokiego poziomu a nie np. w assemblerze*

Chyba, że faktycznie masz jakiś skomplikowany wzór matematyczny

Kopiuj
x * x * 20 + x * 10 + 498 * sqrt(cos(angle) * r + sin(angle) * r2) 

(ten wzór nie ma sensu oczywiście, tak wymyśliłem na poczekaniu)

tutaj będzie miało więcej sensu wydzielenie tego do osobnej funkcji i nazwanie funkcji nazwą wzoru.

*swoją drogą ciekawy trend. W C++ pamiętam ludzie uciekali od funkcji i tworzyli własne operatory (żeby mogli pisząc transformacje geometryczne napisać np. vec1 + vec2 zamiast addVectors(vec1, vec2). A w językach, w których nie da się przeciążać operatorów jak widać ludzie biorą operatory i zamieniają w funkcje. Np. dzisiaj się dowiedziałem, że istnieje biblioteka JS, która wykonuje operację a > 0: npmjs.com/package/is-positive . Widać ludzie zawsze będą niezadowoleni z tego co mają w języku...


edytowany 6x, ostatnio: Adam Boduch
twonek
Ogólnie się zgadzam, tylko przykład moim zdaniem nietrafiony. Ta wydzielona funkcja to nie odpowiednik modulo, tylko faktu, że liczba jest parzysta, przez co nie jest aż taka absurdalna. Wydzielić pewnie bym nie wydzielił, ale nie kręciłbym nosem przy code review gdybym widział.
LukeJL
Niby tak, jest tu dodatkowa semantyka i jestem w stanie sobie wyobrazić sytuacje, kiedy takie wydzielenie do osobnej funkcji isEven będzie miało duży sens (np. przy programowaniu funkcyjnym, jeśli chcemy podać gdzieś funkcję jako argument - wtedy nawet miałoby sens zrobienie funkcji add , np. tutaj https://jsfiddle.net/erpqujy2/ ). Albo jeśli pracujemy w jakimś frameworków webowym, który posiada system szablonów, w którym operatorów po prostu nie ma i musimy zrobić jakiś filtr i wtedy opakowujemy wszystko w funkcje...
LukeJL
Tak więc nie hejtowałbym za samo wydzielanie takich funkcji, bo to też zależy od konkretnego przypadku (z drugiej strony importowanie jakichś paczek z NPM zamiast napisania z palca isPositive to trochę patologia...)
JU
  • Rejestracja:około 22 lata
  • Ostatnio:około miesiąc
  • Postów:5042
1
Wibowit napisał(a):

Zależy od długości i stopnia wykorzystania. Np 1-linijkowe metody używane w jednym miejscu zwykle nie miałyby sensu - takie metody można zastąpić po prostu zmiennymi. Jednak w wielu przypadkach jednolinijkowe metody mają sens, bo opisują co robi dany kod.
Ale taka metoda już coś wnosi:

Kopiuj
boolean userCanEditItem(User user, Item item) {
  return user.isAdmin() || user.manageableItemTypes.contains(item.type);
}

bo zdecydowanie szybciej jestem w stanie zrozumieć to:

Kopiuj
if (!userCanEditItem(user, item)) {
  throw new Error("illegal operation");
}

Nie chodzi tylko, żeby zrozumieć na pierwszy rzut oka, co to robi. Metoda sprawdzenia, czy użytkownik może edytować element, może się zmienić. I jeśli masz metodę, to zmieniasz tylko w jednym miejscu w aplikacji.

Jeśli fragmentu kodu używasz w wielu miejscach i ten kod ma szansę, żeby kiedyś się zmienić (np. fileExists, userCanEditItem, avgLineWidth), to zdecydowanie metoda ma tu sens.

W innych sytuacjach to wszystko zależy :)

krzysiek050
  • Rejestracja:ponad 12 lat
  • Ostatnio:około 4 lata
  • Postów:1272
1

Jedynym minusem sensownych jednolinijkowych funkcji jest puchnięcie kodu. Ale w nowszych językach jak Scala czy Kotlin, takie właśnie funkcje/wyrażenia można zapisać dosłownie w 1 linijce (nie 3 jak w przykładzie) i czyta się to cudnie. Dlatego uważam że przy dobrym języku jest to dobra praktyka, jeżeli stosujesz kiedy trzeba, a nie wszędzie.

Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)