Narzędzia użytkownika

Narzędzia witryny


ewdrstyle

Różnice

Różnice między wybraną wersją a wersją aktualną.

Odnośnik do tego porównania

Both sides previous revision Poprzednia wersja
Nowa wersja
Poprzednia wersja
ewdrstyle [2014/11/15 15:24]
t.zoltak
ewdrstyle [2016/10/03 21:16] (aktualna)
t.zoltak [Zasady formatowania kodu R w projekcie EWD]
Linia 1: Linia 1:
 +======Dobre praktyki tworzenia kodu======
 +
 =====Zasady formatowania kodu R w projekcie EWD===== =====Zasady formatowania kodu R w projekcie EWD=====
  
-  * Zasadniczo trzymamy się zasad z [[https://​google-styleguide.googlecode.com/svn/trunk/​Rguide.xml|Google'​s R Style Guide]]+  * Zasadniczo trzymamy się zasad z [[https://​google.github.io/styleguide/​Rguide.xml|Google'​s R Style Guide]]
   * Z następującymi wyjątkami:   * Z następującymi wyjątkami:
     - jako operatora przypisania wartości używamy '​='​ a nie '​%%<​-%%';​     - jako operatora przypisania wartości używamy '​='​ a nie '​%%<​-%%';​
Linia 13: Linia 15:
     - Przy wykonywaniu zapytań do bazy trzymamy się [[ewdsql|wytycznych]].     - Przy wykonywaniu zapytań do bazy trzymamy się [[ewdsql|wytycznych]].
     - Piszemy funkcje, które nie sięgają do zmiennych, które nie zostały im przekazane jako parametry.     - Piszemy funkcje, które nie sięgają do zmiennych, które nie zostały im przekazane jako parametry.
-      * Dotyczy to również funkcji anonimowych! <​code>​wektor = c('​a',​ '​b',​ c')+      * Dotyczy to również funkcji anonimowych!<​code>​ 
 +wektor = c('​a',​ '​b',​ c')
 # Źle # Źle
 wynik = apply(1:3, function(x){ wektor[x] }) wynik = apply(1:3, function(x){ wektor[x] })
Linia 23: Linia 26:
   wynik[i] = wektor[i]   wynik[i] = wektor[i]
 }</​code>​ }</​code>​
-      * W przypadku wykorzystania funkcji takich jak //​subset()//​ czy //​summarise()//​ używamy funkcji //get()// do oznaczenia, że chcemy wykorzystać kolumnę z obrabianego data frame'​a,​ a nie obiekt z zewnętrznego (wobec tego data frame'​a) środowiska. <​code>​dane = data.frame(a = rep(1:2, 5), b = 1:10)+      * W przypadku wykorzystania funkcji takich jak //​subset()//​ czy //​summarise()//​ używamy funkcji //get()// do oznaczenia, że chcemy wykorzystać kolumnę z obrabianego data frame'​a,​ a nie obiekt z zewnętrznego (wobec tego data frame'​a) środowiska.<​code>​ 
 +dane = data.frame(a = rep(1:2, 5), b = 1:10)
 # Źle # Źle
 agr = ddply(dane, ~a, summarise, sr = mean(b)) agr = ddply(dane, ~a, summarise, sr = mean(b))
Linia 30: Linia 34:
 agr = ddply(dane, ~a, summarise, sr = mean(get("​b"​))) agr = ddply(dane, ~a, summarise, sr = mean(get("​b"​)))
 podzb = subset(dane,​ get("​a"​) == 1)</​code>​ podzb = subset(dane,​ get("​a"​) == 1)</​code>​
 +    - Ciało funkcji anonimowych zawsze otaczamy nawiasami klamrowymi.<​code>​
 +# Źle
 apply(tablica,​ 1, funtion(x) max(x) - min(x)) apply(tablica,​ 1, funtion(x) max(x) - min(x))
 # Dobrze # Dobrze
Linia 50: Linia 56:
 }) })
 zupelnie_prosta_funkcja(arg1,​ arg2) zupelnie_prosta_funkcja(arg1,​ arg2)
- 
  
 # Źle # Źle
Linia 62: Linia 67:
       * łamiemy do nowego wiersza ciała wszelkich nietrywialnych funkcji anonimowych (tzn. zawierających coś więcej niż prostą operację arytmetyczną lub pojedyncze wywołanie funkcji, której parametrem wywołania nie jest żadna inna funkcja);       * łamiemy do nowego wiersza ciała wszelkich nietrywialnych funkcji anonimowych (tzn. zawierających coś więcej niż prostą operację arytmetyczną lub pojedyncze wywołanie funkcji, której parametrem wywołania nie jest żadna inna funkcja);
       * łamiemy do nowego wiersza argumenty wywołania funkcji, jeśli jest ich zbyt wiele;       * łamiemy do nowego wiersza argumenty wywołania funkcji, jeśli jest ich zbyt wiele;
 +      * przy korzystaniu z magrittr-owego operatora %>% (stosowanego w szczególności przy korzystaniu z pakietu //dplyr//) łamiemy linię po każdym jego zastosowaniu,​ chyba że w danym ciągu poleceń jest on wykorzystywany tylko raz (łączy ze sobą dokładnie dwie operacje; z tym że wtedy należy też stosować się do reguły o długości linii);<​code>​
 +# Źle
 +dane = select(dane,​ kolumna1, kolumna2) %>% filter(kolumna2 > 0) %>% summarise(koluma3 = kolumna1 / kolumna2)
 +# Dobrze
 +dane = select(dane,​ kolumna1, kolumna2) %>%
 +  filter(kolumna2 > 0) %>%
 +  summarise(koluma3 = kolumna1 / kolumna2)
 +</​code>​
       * za regułę kciuka przyjmujemy,​ że nadmiernie długa linia to linia o więcej niż 80 znakach.       * za regułę kciuka przyjmujemy,​ że nadmiernie długa linia to linia o więcej niż 80 znakach.
  
 +=====Weryfikacja poprawności argumentów funkcji (run-time testing)=====
 +
 +====Ogólne zasady weryfikacji argumentów funkcji====
 +
 +  * Generalnie przyjmujemy zasadę, że **funkcje powinny weryfikować poprawność przekazywanych do nich argumentów**. W przypadku tworzenia pakietów zasada ta powinna być bezwzględnie przestrzegana w odniesieniu do funkcji, które są eksportowane.
 +  * Jeżeli w funkcji implementowana jest opcjonalna konwersja typów argumentów (np. jeśli argument powinien być wektorem liczb całkowitych,​ ale jest wektorem logicznym, można skonwertować go na wektor liczb całkowitych),​ to **dokonanie konwersji typów powinno wiązać się z wygenerowanie ostrzeżenia widocznego dla użytkownika**.
 +  * Minimalny zakres weryfikacji obejmuje:
 +    * Zgodność typów (w przypadku argumentów o bardziej złożonej strukturze, ale posiadających przypisane klasy - zgodność klas).
 +    * Zakres dozwolonych wartości - jeśli dotyczy.
 +    * Długość (liczba elementów) - jeśli dotyczy (odnosi się to głównie do parametrów sterujących procesem, które z założenia mają być skalarami).
 +  * Ewentualne rozszerzanie zakresu weryfikacji ponad wyżej wymienione (typowo bardziej szczegółowe sprawdzanie struktury złożonych argumentów) należy rozważać w odniesieniu do:
 +    * Skutków niewykrycia niezgodności.
 +    * Szacowanego prawdopodobieństwa wystąpienia niezgodności.
 +    * Złożoności kodu weryfikującego w stosunku do złożoności całej funkcji.
 +    * Obciążenia obliczeniowego związanego z weryfikacją.
 +
 +====Metody weryfikacji argumentów funkcji====
 +
 +Spośród opisanych niżej metod **preferowane jest wykorzystanie funkcji pakietu //​assertive//​** w rozsądnym połączeniu z użyciem warunków do obsługi bardziej skomplikowanych sytuacji (w szczególności ostrzeżeń i konwersji typów, jeśli funkcja takowe wykonuje).
 +
 +[[pakietassert|Przewodnik po funkcjach pakietu assertive.]]
 +
 +===Stosowanie warunków===
 +
 +  * **Zalety:**
 +    * Elastyczne.
 +    * Umożliwia zwracanie czytelnych komunikatów o błędach i/lub ostrzeżeń.
 +  * **Wady:**
 +    * Wymaga pisania bardzo dużo kodu, co jest uciążliwe i często czyni kod nieczytelnym.
 +  * **Przykład:​**<​code>​moja_funkcja = function(x) {
 +  if (any(is.na(x)) {
 +    stop("​Argument '​x'​ nie może zawierać braków danych!"​)
 +  } else {
 +    return(x)
 +  }
 +}</​code>​
 +
 +===Stosowanie funkcji stopifnot()===
 +
 +  * **Zalety:**
 +    * W typowych, niezbyt złożonych sytuacjach, krótki i czytelny kod.
 +  * **Wady:**
 +    * Niezbyt przyjazne użytkownikowi komunikaty o błędach.
 +    * Obsługa wyłącznie błędów (ale ostrzeżeń już nie).
 +  * **Przykład:​**<​code>​moja_funkcja = function(x) {
 +  stopifnot(all(!is.na(x))
 +  return(x)
 +}</​code>​
 +
 +===Stosowanie funkcji pakietu assertive===
 +
 +[[pakietassert|Przewodnik po funkcjach pakietu assertive.]]
 +
 +  * **Zalety:**
 +    * Krótki i czytelny kod w szerokim zakresie zastosowań (nieco szerszym niż //​stopifnot()//​).
 +      * Wiele warunków i formatów, z którymi można sprawdzać zgodność.
 +      * Automatyzacja najbardziej typowych kombinacji warunków w pojedynczych funkcjach.
 +    * Przyjazne użytkownikowi komunikaty o błędach.
 +  * **Wady:**
 +    * Nic nie będzie równie elastyczne, jak używanie //if//.
 +    * Wymaga trochę czasu, żeby zorientować się w mnogości funkcji udostępnianych przez pakiet.
 +  * **Przykład:​**<​code>​moja_funkcja = function(x) {
 +  assert_all_are_not_na(x)
 +  return(x)
 +}</​code>​
ewdrstyle.1416061458.txt.gz · ostatnio zmienione: 2014/11/15 15:24 przez t.zoltak